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?

Null Pointer Exception
fonte

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

Kevin Coppock
fonte
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

kouretinho
fonte
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);
}
Rohit Rathore
fonte
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) 
David Miguel
fonte