¿Cambiar el margen derecho de una vista mediante programación?

173

¿Se puede cambiar este atributo dinámicamente en código Java?

android:layout_marginRight

Tengo un TextView, que tiene que cambiar su posición dinámicamente algunos píxeles a la izquierda.

¿Cómo hacerlo programáticamente?

Excepción de puntero nulo
fuente

Respuestas:

463

EDITAR: Una forma más genérica de hacer esto que no depende del tipo de diseño (aparte de eso es un tipo de diseño que admite márgenes):

public static void setMargins (View v, int l, int t, int r, int b) {
    if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
        p.setMargins(l, t, r, b);
        v.requestLayout();
    }
}

Debe consultar los documentos para TextView . Básicamente, querrás obtener el objeto LayoutParams de TextView, modificar los márgenes y luego volver a configurarlo en TextView. Suponiendo que está en un diseño lineal, intente algo como esto:

TextView tv = (TextView)findViewById(R.id.my_text_view);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tv.getLayoutParams();
params.setMargins(0, 0, 10, 0); //substitute parameters for left, top, right, bottom
tv.setLayoutParams(params);

No puedo probarlo en este momento, por lo que mi lanzamiento puede estar un poco apagado, pero los LayoutParams son los que deben modificarse para cambiar el margen.

NOTA

No olvide que si su TextView está dentro, por ejemplo, un RelativeLayout , uno debería usar RelativeLayout.LayoutParams en lugar de LinearLayout.LayoutParams

Kevin Coppock
fuente
39
Solo para elaborar su respuesta en caso de que otras personas estén buscando esto. Si está creando TextView mediante programación, también debe crear un nuevo objeto LinearLayout.LayoutParams, en lugar de intentar obtener uno a través de .getLayoutParams ();
Ares
Esto funciona de maravilla, y parece que establece los márgenes en píxeles. ¿Es posible configurarlo en dp?
SirRupertIII
3
@KKendall: Simplemente convierta su DP a PX primero.
Kevin Coppock
Según su NOTA: tengo dudas. Si la vista de texto o un botón está dentro de una fila de la tabla? Entonces, ¿qué debo usar en lugar de Diseño relativo, Diseño de tabla?
tejas
1
En relación con la nota, puede enviar tv.getLayoutParams () a ViewGroup.MarginLayoutParams. De esta manera, no importa qué diseño sea el padre, siempre que implemente márgenes
Radu Simionescu
17

Use LayoutParams (como ya se explicó). Sin embargo, tenga cuidado con qué LayoutParams elegir. De acuerdo con https://stackoverflow.com/a/11971553/3184778 "debe usar el que se relaciona con el PADRE de la vista en la que está trabajando, no con la vista real"

Si, por ejemplo, TextView está dentro de un TableRow, debe usar TableRow.LayoutParams en lugar de RelativeLayout o LinearLayout

kouretinho
fuente
¡Gracias por aclararlo!
Scott Biggs
1
realmente apesta que tengas que conocer el destino del cuadro de texto para establecer los márgenes ... pensarías que habría una solución que es independiente del destino.
TatiOverflow
10

Use esta función para configurar todo tipo de márgenes

      public void setViewMargins(Context con, ViewGroup.LayoutParams params,      
       int left, int top , int right, int bottom, View view) {

    final float scale = con.getResources().getDisplayMetrics().density;
    // convert the DP into pixel
    int pixel_left = (int) (left * scale + 0.5f);
    int pixel_top = (int) (top * scale + 0.5f);
    int pixel_right = (int) (right * scale + 0.5f);
    int pixel_bottom = (int) (bottom * scale + 0.5f);

    ViewGroup.MarginLayoutParams s = (ViewGroup.MarginLayoutParams) params;
    s.setMargins(pixel_left, pixel_top, pixel_right, pixel_bottom);

    view.setLayoutParams(params);
}
Rohit Rathore
fuente
2
¿Por qué los 0.5f adicionales?
Behelit
2
@ behelit Sé que es tarde, pero para cualquiera que esté mirando ... cuando lanzas un flotador a un int, el flotador se redondea. 0.0 -> 0.4 se redondea a 0 mientras 0.5 -> 0.9 se redondea a 1. Esto puede crear inconsistencias en las entradas finales. Para evitar esto, agregar 0.5 asegura que todo el redondeo sea 1. ¿Por qué? digamos que su flotador es 0.3: 0.3 + 0.5 = 0.8 que se redondea a 1. Digamos que su flotador es 0.8: 0.8 + 0.5 = 1.3 que se redondea a 1. Ahora puede estar seguro en su conocimiento del redondeo final (NOTA LATERAL: agregamos 0.5 en lugar de restar para evitar obtener un int negativo)
Psest328
7

Actualización: Android KTX

El módulo Core KTX proporciona extensiones para bibliotecas comunes que forman parte del marco de Android, androidx.core.viewentre ellas.

dependencies {
    implementation "androidx.core:core-ktx:{latest-version}"
}

Las siguientes funciones de extensión son útiles para manejar los márgenes:

Establece los márgenes de todos los ejes en la ViewGroup's MarginLayoutParams. (La dimensión debe proporcionarse en píxeles, consulte la última sección si desea trabajar con dp)

inline fun MarginLayoutParams.setMargins(@Px size: Int): Unit
// E.g. 16px margins
val params = (myView.layoutParams as ViewGroup.MarginLayoutParams)
params.setMargins(16)

Actualiza los márgenes en el ViewGroup's ViewGroup.MarginLayoutParams.

inline fun MarginLayoutParams.updateMargins(
    @Px left: Int = leftMargin, 
    @Px top: Int = topMargin, 
    @Px right: Int = rightMargin, 
    @Px bottom: Int = bottomMargin
): Unit
// Example: 8px left margin 
params.updateMargins(left = 8)

Actualiza los márgenes relativos en los ViewGroup's MarginLayoutParams(inicio / final en lugar de izquierda / derecha).

inline fun MarginLayoutParams.updateMarginsRelative(
    @Px start: Int = marginStart, 
    @Px top: Int = topMargin, 
    @Px end: Int = marginEnd, 
    @Px bottom: Int = bottomMargin
): Unit
// E.g: 8px start margin 
params.updateMargins(start = 8)

Las siguientes propiedades de extensión son útiles para obtener los márgenes actuales:

inline val View.marginBottom: Int
inline val View.marginEnd: Int
inline val View.marginLeft: Int
inline val View.marginRight: Int
inline val View.marginStart: Int
inline val View.marginTop: Int
// E.g: get margin bottom
val bottomPx = myView1.marginBottom
  • Usando en dplugar de px:

Si desea trabajar con dp(píxeles independientes de la densidad) en lugar de px, primero deberá convertirlos. Puede hacerlo fácilmente con la siguiente propiedad de extensión:

val Int.px: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

Luego puede llamar a las funciones de extensión anteriores como:

params.updateMargins(start = 16.px, end = 16.px, top = 8.px, bottom = 8.px)
val bottomDp = myView1.marginBottom.dp

Vieja respuesta:

En Kotlin puede declarar una función de extensión como:

fun View.setMargins(
    leftMarginDp: Int? = null,
    topMarginDp: Int? = null,
    rightMarginDp: Int? = null,
    bottomMarginDp: Int? = null
) {
    if (layoutParams is ViewGroup.MarginLayoutParams) {
        val params = layoutParams as ViewGroup.MarginLayoutParams
        leftMarginDp?.run { params.leftMargin = this.dpToPx(context) }
        topMarginDp?.run { params.topMargin = this.dpToPx(context) }
        rightMarginDp?.run { params.rightMargin = this.dpToPx(context) }
        bottomMarginDp?.run { params.bottomMargin = this.dpToPx(context) }
        requestLayout()
    }
}

fun Int.dpToPx(context: Context): Int {
    val metrics = context.resources.displayMetrics
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), metrics).toInt()
}

Entonces puedes llamarlo así:

myView1.setMargins(8, 16, 34, 42)

O:

myView2.setMargins(topMarginDp = 8) 
David Miguel
fuente