Changer la bonne marge d'une vue par programme?

173

Cet attribut peut-il être modifié dynamiquement dans le code Java?

android:layout_marginRight

J'ai un TextView, qui doit changer sa position de quelques pixels vers la gauche dynamiquement.

Comment le faire par programmation?

NullPointerException
la source

Réponses:

463

EDIT: Une manière plus générique de faire cela qui ne repose pas sur le type de mise en page (à part le fait qu'il s'agit d'un type de mise en page qui prend en charge les marges):

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

Vous devriez vérifier les documents pour TextView . Fondamentalement, vous voudrez obtenir l'objet LayoutParams de TextView et modifier les marges, puis le redéfinir sur TextView. En supposant que c'est dans un LinearLayout, essayez quelque chose comme ceci:

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

Je ne peux pas le tester pour le moment, donc mon casting est peut-être un peu décalé, mais les LayoutParams doivent être modifiés pour changer la marge.

REMARQUE

N'oubliez pas que si votre TextView est à l'intérieur, par exemple, d'un RelativeLayout , il faut utiliser RelativeLayout.LayoutParams au lieu de LinearLayout.LayoutParams

Kevin Coppock
la source
39
Juste pour développer votre réponse au cas où d'autres personnes le rechercheraient. Si vous créez le TextView par programme, vous devez également créer un nouvel objet LinearLayout.LayoutParams, au lieu d'essayer d'en obtenir un via .getLayoutParams ();
Ares
Cela fonctionne à merveille, et il semble que cela définit les marges en pixels. Est-il possible de le définir dans dp?
SirRupertIII
3
@KKendall: convertissez d'abord votre DP en PX .
Kevin Coppock
Selon votre note: j'ai un doute. Si la vue de texte ou un bouton se trouve à l'intérieur d'une ligne de tableau? Alors, que dois-je utiliser à la place de la disposition relative, de la disposition du tableau?
tejas
1
Lié à la note, vous pouvez simplement lancer tv.getLayoutParams () vers ViewGroup.MarginLayoutParams. De cette façon, peu importe la mise en page du parent, tant qu'il implémente des marges
Radu Simionescu
17

Utilisez LayoutParams (comme expliqué déjà). Cependant, faites attention aux LayoutParams à choisir. Selon https://stackoverflow.com/a/11971553/3184778 "vous devez utiliser celui qui se rapporte au PARENT de la vue sur laquelle vous travaillez, pas la vue réelle"

Si, par exemple, le TextView est à l'intérieur d'un TableRow, vous devez utiliser TableRow.LayoutParams au lieu de RelativeLayout ou LinearLayout

kouretinho
la source
Merci de clarifier!
Scott Biggs
1
ça craint vraiment que vous deviez connaître la destination de la zone de texte pour définir les marges ... vous penseriez qu'il y aurait une solution indépendante de la destination.
TatiOverflow
10

Utilisez cette fonction pour définir tous les types de marges

      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
la source
2
Pourquoi le 0.5f supplémentaire?
behelit
2
@behelit Je sais que c'est tard, mais pour tous ceux qui cherchent ... quand vous lancez un flotteur sur un int, le flotteur tourne. 0,0 -> 0,4 ​​arrondit à 0 tandis que 0,5 -> 0,9 arrondit à 1. Cela peut créer des incohérences dans les derniers points. Pour éviter cela, ajouter 0,5 garantit que tout arrondi est égal à 1. Pourquoi? dites que votre flotteur est de 0,3: 0,3 + 0,5 = 0,8 qui arrondit à 1. Disons que votre flotteur est de 0,8: 0,8 + 0,5 = 1,3 qui arrondit à 1. Vous pouvez maintenant être sûr de votre connaissance de l'arrondi final (NOTE SIDE: nous ajoutons 0,5 plutôt que de soustraire pour éviter d'obtenir un
entier
8

Mise à jour: Android KTX

Le module Core KTX fournit des extensions pour les bibliothèques courantes qui font partie du framework Android, androidx.core.viewparmi elles.

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

Les fonctions d'extension suivantes sont pratiques pour gérer les marges:

Définit les marges de tous les axes dans le ViewGroup's MarginLayoutParams. (La dimension doit être fournie en pixels, voir la dernière section si vous souhaitez travailler avec dp)

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

Met à jour les marges dans le 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)

Met à jour les marges relatives dans les ViewGroup's MarginLayoutParams(début / fin au lieu de gauche / droite).

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)

Les propriétés d'extension suivantes sont pratiques pour obtenir les marges actuelles:

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
  • Utiliser dpau lieu de px:

Si vous souhaitez travailler avec dp(pixels indépendants de la densité) au lieu de px, vous devrez d'abord les convertir. Vous pouvez facilement le faire avec la propriété d'extension suivante:

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

Ensuite, vous pouvez appeler les fonctions d'extension précédentes telles que:

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

Ancienne réponse:

Dans Kotlin, vous pouvez déclarer une fonction d'extension comme:

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

Ensuite, vous pouvez l'appeler comme:

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

Ou:

myView2.setMargins(topMarginDp = 8) 
David Miguel
la source