Establecer márgenes en un LinearLayout mediante programación


266

Estoy tratando de usar Java ( no XML ) para crear un diseño lineal con botones que llenan la pantalla y tienen márgenes. Aquí hay un código que funciona sin márgenes:

LinearLayout buttonsView = new LinearLayout(this);
buttonsView.setOrientation(LinearLayout.VERTICAL);
for (int r = 0; r < 6; ++r) {
    Button btn = new Button(this);
    btn.setText("A");

    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT); // Verbose!
    lp.weight = 1.0f; // This is critical. Doesn't work without it.
    buttonsView.addView(btn, lp);
}

ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
setContentView(buttonsView, lp);

Eso funciona bien, pero ¿cómo demonios le das a los botones márgenes para que haya espacio entre ellos? Intenté usarlo LinearLayout.MarginLayoutParams, pero eso no tiene weightmiembro, así que no es bueno. Y tampoco funciona si lo pasa lpen su constructor.

¿Es esto imposible? Porque seguro que lo parece, y no sería la primera tarea de diseño de Android que solo puedes hacer en XML.


1
developer.android.com/reference/android/view/… , int, int, int) En lugar de layoutParams.setMargins (30, 20, 30, 0); pones layoutParams.setMargins (30dp, 20dp, 30dp, 0dp);
DarthestVader

3
setMargins toma int como argumentos ... solo puede proporcionar "dp" usando atributos xml
jyavenard

Respuestas:


496

Aquí hay un pequeño código para lograrlo:

LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
     LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);

layoutParams.setMargins(30, 20, 30, 0);

Button okButton=new Button(this);
okButton.setText("some text");
ll.addView(okButton, layoutParams);

66
gracias por una muestra de código al punto - mucho más beneficioso que solo descripciones
Someone Somewhere

25
Parece que los parámetros de margen están configurados en píxeles. ¿Alguna forma de configurarlos en dps?
Artem Russakovskii

30
@ArtemRussakovskii Como la mayoría de las funciones en Android, toman píxeles. Sugiero una función de utilidad global que convierte las inmersiones a px. Esto es lo que he hecho en todas mis aplicaciones. La API de Android apesta.
mxcl

77
@ MaxHowell Eso es lo que terminé haciendo. Es increíble que a veces falten cosas básicas como esa.
Artem Russakovskii

55
@ArtemRussakovskii: use TypedValue.applyDimension (...) para convertir DIP a PX. Ver stackoverflow.com/questions/2238883/…
Gautam

64

Entonces eso funciona bien, pero ¿cómo diablos le das a los botones márgenes para que haya espacio entre ellos?

Llama setMargins() el LinearLayout.LayoutParamsobjeto.

Intenté usar LinearLayout.MarginLayoutParams, pero eso no tiene un miembro de peso, por lo que no es bueno.

LinearLayout.LayoutParamses una subclase de LinearLayout.MarginLayoutParams, como se indica en el documentación .

¿Es esto imposible?

No.

no sería la primera tarea de diseño de Android que solo puedes hacer en XML

Le invitamos a proporcionar prueba de este reclamo.

Personalmente, no conozco nada que solo se pueda lograr a través de XML y no a través de métodos Java en el SDK. De hecho, por definición, todo debe ser factible a través de Java (aunque no necesariamente a través de métodos alcanzables por SDK), ya que XML no es código ejecutable. Pero, si está al tanto de algo, indíquelo, porque es un error en el SDK que debería solucionarse algún día.


2
Ja, ok, ahora entiendo. Se estaba perdiendo un poco en el sistema de diseño, que es bastante complicado. No creo que haya de todos modos establecer layout_widgth / height en tiempo de ejecución.
Timmmm

2
Y no hay forma de establecer el estilo: stackoverflow.com/questions/2016249/…
Timmmm

1
No he tenido problemas para configurar el ancho y la altura en tiempo de ejecución a través de LayoutPararms. Tengo términos de estilos ... sí, bueno, hay una razón por la que no los uso. :-)
CommonsWare

66
Quiero saber por qué es tan PITA generar programáticamente una interfaz de usuario
alguien en algún lugar

3
Me llevó años darme cuenta de que, de hecho, hace unos días importé los LayoutParams incorrectos que no admitían márgenes ... Al leer estas respuestas, decidí eliminar mi importación. Hay más de 10 opciones D: elegí linearLayout.LayoutParams. Trabajos.
Doomsknight

31

Para agregar márgenes directamente a los elementos (algunos elementos permiten la edición directa de los márgenes), puede hacer lo siguiente:

LayoutParams lp = ((ViewGroup) something).getLayoutParams();
if( lp instanceof MarginLayoutParams )
{
    ((MarginLayoutParams) lp).topMargin = ...;
    ((MarginLayoutParams) lp).leftMargin = ...;
    //... etc
}
else
    Log.e("MyApp", "Attempted to set the margins on a class that doesn't support margins: "+something.getClass().getName() );

... esto funciona sin necesidad de saber / editar el diseño circundante. Tenga en cuenta la comprobación "instanceof" en caso de que intente ejecutar esto contra algo que no admite márgenes.


2
Es exactamente lo que estoy buscando.
djdance

21

Debido a la variación en la densidad de píxeles de la pantalla del dispositivo, es bueno usar siempre la DIPunidad para establecer el margen mediante programación. Como abajo_

//get resources
Resources r = getResources();
float pxLeftMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, r.getDisplayMetrics());
float pxTopMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, r.getDisplayMetrics());
float pxRightMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, r.getDisplayMetrics());
float pxBottomMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, r.getDisplayMetrics());

//get layout params...
LayoutParams params=new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.setMargins(Math.round(pxLeftMargin), Math.round(pxTopMargin), Math.round(pxRightMargin), Math.round(pxBottomMargin));

//set margin...
yourLayoutTOsetMargin.setLayoutParams(params); 

Espero que esto ayude.


10

He configurado márgenes directamente usando el siguiente código

LinearLayout layout = (LinearLayout)findViewById(R.id.yourrelative_layout);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);            
params.setMargins(3, 300, 3, 3); 
layout.setLayoutParams(params);

Lo único aquí es notar que LayoutParamsdebe importarse para el siguiente paquete android.widget.RelativeLayout.LayoutParams, o de lo contrario habrá un error.


7

Prueba esto

 LayoutParams params = new LayoutParams(
            LayoutParams.WRAP_CONTENT,      
            LayoutParams.WRAP_CONTENT
    );
    params.setMargins(left, top, right, bottom);
    yourbutton.setLayoutParams(params);

7
 MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
 layoutParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);

2
"Si bien este código puede responder la pregunta, es mejor incluir la explicación del código aquí.
xenteros

4

Prueba esto:

MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
params.width = 250;
params.leftMargin = 50;
params.topMargin = 50;

3
/*
 * invalid margin
 */
private void invalidMarginBottom() {
    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) frameLayoutContent.getLayoutParams();
    lp.setMargins(0, 0, 0, 0);
    frameLayoutContent.setLayoutParams(lp);
}

debe tener en cuenta el tipo de viewGroup de la vista. En el código anterior, por ejemplo, quiero cambiar el margen de frameLayout, y el grupo de vista de frameLayout es RelativeLayout , por lo que debe convertirse a (RelativeLayout.LayoutParams)


0

Aquí una solución de línea única:

((LinearLayout.LayoutParams) yourLinearLayout.getLayoutParams()).marginToAdd = ((int)(Resources.getSystem().getDisplayMetrics().density * yourDPValue));
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.