Alterar a margem direita de uma exibição programaticamente?


173

Este atributo pode ser alterado dinamicamente no código Java?

android:layout_marginRight

Eu tenho um TextView, que tem que mudar sua posição alguns pixels para a esquerda dinamicamente.

Como fazer isso programaticamente?

Respostas:


463

EDIT: Uma maneira mais genérica de fazer isso que não depende do tipo de layout (exceto que é um tipo de layout que suporta margens):

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();
    }
}

Você deve verificar os documentos para o TextView . Basicamente, você deseja obter o objeto LayoutParams do TextView e modificar as margens e depois defini-lo novamente para o TextView. Supondo que ele esteja em um LinearLayout, tente algo como isto:

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);

Não posso testá-lo agora, então minha transmissão pode demorar um pouco, mas o LayoutParams é o que precisa ser modificado para alterar a margem.

NOTA

Não se esqueça de que, se seu TextView estiver dentro, por exemplo, de um RelativeLayout , use RelativeLayout.LayoutParams em vez de LinearLayout.LayoutParams


39
Apenas para elaborar sua resposta, caso outras pessoas estejam procurando por isso. Se você estiver criando o TextView programaticamente, também precisará criar um novo objeto LinearLayout.LayoutParams, em vez de tentar obtê-lo por meio de .getLayoutParams ();
— Ares

Isso funciona demais, e parece que define as margens em pixels. É possível configurá-lo em dp?
— 12269 SirRupertIII

3
@KKendall: Basta converter seu DP para PX primeiro.
— 22812 Kevin Coppock

Conforme sua NOTA: tenho dúvidas. Se a visualização de texto ou um botão estiver dentro de uma linha da tabela? Então, o que devo usar em vez de Layout relativo, Layout de tabela?
— Tejas

1
Relacionado à nota, você pode simplesmente transmitir tv.getLayoutParams () para ViewGroup.MarginLayoutParams. Desta forma, não importa o que o layout é o Parrent, contanto que implementa margens
— Radu Simionescu

17

Use LayoutParams (como já explicado). No entanto, tenha cuidado com o LayoutParams para escolher. De acordo com https://stackoverflow.com/a/11971553/3184778 "você precisa usar aquele que se relaciona com o PAI da visualização em que está trabalhando, não da visualização real"

Se, por exemplo, o TextView estiver dentro de um TableRow, você precisará usar TableRow.LayoutParams em vez de RelativeLayout ou LinearLayout


Obrigado por esclarecer!
— Scott Biggs

1
é realmente péssimo que você precise conhecer o destino da caixa de texto para definir as margens ... você pensaria que haveria uma solução independente do destino.
— TatiOverflow

10

Use esta função para definir todos os tipos de margens

      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);
}

2
Por que o 0.5f adicional?
— behelit

2
@behelit Eu sei que é tarde, mas para quem procura ... quando você lança um float para um int, o float é arredondado. 0,0 -> 0,4 ​​arredonda para 0, enquanto 0,5 -> 0,9 arredonda para 1. Isso pode criar inconsistências nas entradas finais. Para evitar isso, adicionar 0,5 garante que todo o arredondamento seja 1. Por que? diga que seu flutuador é 0,3: 0,3 + 0,5 = 0,8, que arredonda até 1. Diga que seu flutuador é 0,8: 0,8 + 0,5 = 1,3, que arredonda para baixo para 1. Agora você pode estar seguro de seu conhecimento do arredondamento final (NOTA LATERAL: somarmos 0,5 em vez de subtrair para evitar um int negativo)
— Psest328

7

Atualização: Android KTX

O módulo Core KTX fornece extensões para bibliotecas comuns que fazem parte da estrutura do Android, androidx.core.viewentre elas.

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

As seguintes funções de extensão são úteis para lidar com margens:

Define as margens de todos os eixos nos ViewGroup's MarginLayoutParams. (A dimensão deve ser fornecida em pixels; consulte a última seção se você quiser trabalhar com o dp)

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

Atualizações as margens no 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)

Atualizações as margens relativas no ViewGroup's MarginLayoutParams(início / fim, em vez de esquerda / direita).

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)

As seguintes propriedades de extensão são úteis para obter as margens atuais:

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 em dpvez de px:

Se você deseja trabalhar com dp(pixels independentes da densidade) em vez de px, precisará convertê-los primeiro. Você pode fazer isso facilmente com a seguinte propriedade de extensão:

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

Em seguida, você pode chamar as funções de extensão anteriores, como:

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

Resposta antiga:

No Kotlin, você pode declarar uma função de extensão 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()
}

Então você pode chamar assim:

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

Ou:

myView2.setMargins(topMarginDp = 8) 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.