Cambiare il margine giusto di una vista a livello di codice?


173

Questo attributo può essere modificato in modo dinamico nel codice Java?

android:layout_marginRight

Ho un TextView, che deve cambiare dinamicamente la sua posizione di alcuni pixel a sinistra.

Come farlo a livello di codice?

Risposte:


463

EDIT: un modo più generico di fare ciò che non si basa sul tipo di layout (a parte questo è un tipo di layout che supporta i margini):

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

È necessario controllare i documenti per TextView . Fondamentalmente, vorrai ottenere l'oggetto LayoutParams di TextView e modificare i margini, quindi ripristinarlo su TextView. Supponendo che sia in un LinearLayout, prova qualcosa del genere:

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

Non posso provarlo in questo momento, quindi il mio casting potrebbe essere un po 'spento, ma LayoutParams è ciò che deve essere modificato per cambiare il margine.

NOTA

Non dimenticare che se TextView è all'interno, ad esempio, di RelativeLayout , si dovrebbe usare RelativeLayout.LayoutParams invece di LinearLayout.LayoutParams


39
Solo per elaborare la tua risposta nel caso in cui altre persone lo stiano cercando. Se stai creando TextView a livello di codice, devi creare anche un nuovo oggetto LinearLayout.LayoutParams, invece di provare a estrarne uno tramite .getLayoutParams ();
Ares,

Funziona alla grande e sembra che imposta i margini in pixel. È possibile impostarlo in dp?
SirRupertIII,


Come da NOTA: ho dei dubbi. Se la visualizzazione di testo o un pulsante si trova all'interno di una riga della tabella? Quindi cosa devo usare invece di Layout relativo, Layout tabella?
Tejas,

1
In relazione alla nota, puoi semplicemente trasmettere tv.getLayoutParams () a ViewGroup.MarginLayoutParams. In questo modo non importa quale sia il layout del pappagallo, a condizione che implementi i margini
Radu Simionescu,

17

Usa LayoutParams (come già spiegato). Tuttavia, fai attenzione a LayoutParams da scegliere. Secondo https://stackoverflow.com/a/11971553/3184778 "è necessario utilizzare quello relativo al GENITORE della vista su cui si sta lavorando, non la vista effettiva"

Se ad esempio TextView si trova all'interno di un TableRow, è necessario utilizzare TableRow.LayoutParams anziché RelativeLayout o LinearLayout


Grazie per il chiarimento!
Scott Biggs,

1
fa davvero schifo dover conoscere la destinazione della casella di testo per impostare i margini ... penseresti che ci sarebbe una soluzione indipendente dalla destinazione.
TatiOverflow,

10

Utilizzare questa funzione per impostare tutti i tipi di margini

      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
Perché lo 0,5f aggiuntivo?
Behelit,

2
@behelit So che è tardi, ma per tutti coloro che guardano ... quando lanci un float su un int, il float gira. 0,0 -> 0,4 ​​round a 0 mentre 0,5 -> 0,9 round a 1. Questo può creare incoerenze negli ultimi finali. Per evitare ciò, l'aggiunta di 0,5 garantisce che tutti gli arrotondamenti siano 1. Perché? supponiamo che il tuo float sia 0,3: 0,3 + 0,5 = 0,8 che arrotonda fino a 1. Supponi che il tuo galleggiante sia 0,8: 0,8 + 0,5 = 1,3 che arrotonda GIÙ a 1. Ora puoi essere al sicuro nella tua conoscenza dell'arrotondamento finale (NOTA LATERALE: aggiungiamo 0,5 anziché sottrarre per evitare di ottenere un int negativo)
Psest328

7

Aggiornamento: Android KTX

Il modulo Core KTX fornisce estensioni per librerie comuni che fanno parte del framework Android, androidx.core.viewtra cui.

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

Le seguenti funzioni di estensione sono utili per gestire i margini:

Imposta i margini di tutti gli assi in ViewGroup's MarginLayoutParams. (La dimensione deve essere fornita in pixel, vedere l'ultima sezione se si desidera lavorare con dp)

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

Gli aggiornamenti dei margini nella 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)

Aggiorna i margini relativi in ViewGroup's MarginLayoutParams(inizio / fine anziché sinistra / destra).

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)

Le seguenti proprietà di estensione sono utili per ottenere i margini correnti:

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
  • Utilizzando dpinvece di px:

Se vuoi lavorare con dp(pixel indipendenti dalla densità) invece di px, dovrai prima convertirli. Puoi farlo facilmente con la seguente proprietà di estensione:

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

Quindi puoi chiamare le funzioni dell'estensione precedente come:

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

Vecchia risposta:

In Kotlin puoi dichiarare una funzione di estensione come:

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

Quindi puoi chiamarlo come:

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

O:

myView2.setMargins(topMarginDp = 8) 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.