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.

Timmmm
fuente
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);
Mauro
fuente
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.

CommonsWare
fuente
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.

Adán
fuente
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.

Rupesh Yadav
fuente
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.

Janith
fuente
7

Prueba esto

 LayoutParams params = new LayoutParams(
            LayoutParams.WRAP_CONTENT,      
            LayoutParams.WRAP_CONTENT
    );
    params.setMargins(left, top, right, bottom);
    yourbutton.setLayoutParams(params);
Karan Bhalodiya
fuente
7
 MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
 layoutParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);
Ginni
fuente
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;
Makvin
fuente
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)

Francis Shi
fuente
0

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

((LinearLayout.LayoutParams) yourLinearLayout.getLayoutParams()).marginToAdd = ((int)(Resources.getSystem().getDisplayMetrics().density * yourDPValue));
Stappo
fuente