Den rechten Rand einer Ansicht programmgesteuert ändern?

172

Kann dieses Attribut in Java-Code dynamisch geändert werden?

android:layout_marginRight

Ich habe eine TextView, die ihre Position einige Pixel nach links dynamisch ändern muss.

Wie geht das programmgesteuert?

NullPointerException
quelle

Antworten:

462

BEARBEITEN: Eine allgemeinere Methode, die nicht vom Layouttyp abhängt (außer dass es sich um einen Layouttyp handelt, der Ränder unterstützt):

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

Sie sollten die Dokumente auf TextView überprüfen . Grundsätzlich möchten Sie das LayoutParams-Objekt von TextView abrufen, die Ränder ändern und dann wieder auf TextView zurücksetzen. Angenommen, es befindet sich in einem LinearLayout, versuchen Sie Folgendes:

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

Ich kann es momentan nicht testen, daher ist mein Casting möglicherweise etwas verschoben, aber die LayoutParams müssen geändert werden, um den Rand zu ändern.

HINWEIS

Vergessen Sie nicht, dass Sie, wenn sich Ihre Textansicht beispielsweise in einem RelativeLayout befindet , RelativeLayout.LayoutParams anstelle von LinearLayout.LayoutParams verwenden sollten

Kevin Coppock
quelle
39
Nur um Ihre Antwort zu erläutern, falls andere Leute danach suchen. Wenn Sie die Textansicht programmgesteuert erstellen, müssen Sie auch ein neues LinearLayout.LayoutParams-Objekt erstellen, anstatt zu versuchen, eines über .getLayoutParams () herauszuholen.
Ares
Dies funktioniert hervorragend und es scheint, als würde es die Ränder in Pixel festlegen. Ist es möglich, es in dp einzustellen?
SirRupertIII
3
@KKendall: Konvertieren Sie einfach zuerst Ihren DP in PX .
Kevin Coppock
Gemäß Ihrem HINWEIS: Ich habe Zweifel. Befindet sich die Textansicht oder eine Schaltfläche in einer Tabellenzeile? Was soll ich dann anstelle von Relativem Layout, Tabellenlayout verwenden?
Tejas
1
Im Zusammenhang mit der Notiz können Sie einfach tv.getLayoutParams () in ViewGroup.MarginLayoutParams umwandeln. Auf diese Weise spielt es keine Rolle, welches Layout der Parrent ist, solange es Ränder implementiert
Radu Simionescu
17

Verwenden Sie LayoutParams (wie bereits erläutert). Achten Sie jedoch darauf, welche LayoutParams Sie auswählen. Laut https://stackoverflow.com/a/11971553/3184778 "müssen Sie diejenige verwenden, die sich auf das ELTERN der Ansicht bezieht, an der Sie arbeiten, nicht die tatsächliche Ansicht."

Befindet sich die Textansicht beispielsweise in einer TableRow, müssen Sie TableRow.LayoutParams anstelle von RelativeLayout oder LinearLayout verwenden

kouretinho
quelle
Danke fürs klarstellen!
Scott Biggs
1
Es ist wirklich schade, dass Sie das Textfeldziel kennen müssen, um die Ränder festzulegen. Sie würden denken, dass es eine Lösung gibt, die vom Ziel unabhängig ist.
TatiOverflow
10

Verwenden Sie diese Funktion, um alle Randtypen festzulegen

      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
quelle
2
Warum die zusätzlichen 0,5f?
siehe
2
@behelit Ich weiß, dass dies spät ist, aber für alle, die suchen ... Wenn Sie einen Float auf einen Int werfen, rundet der Float. 0,0 -> 0,4 ​​Runden auf 0, während 0,5 -> 0,9 Runden auf 1 gehen. Dies kann zu Inkonsistenzen in den endgültigen Ints führen. Um dies zu verhindern, wird durch Hinzufügen von 0,5 sichergestellt, dass alle Rundungen auf 1 erfolgen. Warum? Angenommen, Ihr Float ist 0,3: 0,3 + 0,5 = 0,8, was auf 1 aufrundet. Angenommen, Ihr Float ist 0,8: 0,8 + 0,5 = 1,3, was auf 1 abrundet. Jetzt können Sie sicher sein, dass Sie die endgültige Rundung kennen (SEITLICHER HINWEIS: wir addieren 0,5 anstatt zu subtrahieren, um ein negatives int zu vermeiden)
Psest328
7

Update: Android KTX

Das Core KTX-Modul bietet Erweiterungen für allgemeine Bibliotheken, die unter anderem Teil des Android-Frameworks sind androidx.core.view.

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

Die folgenden Erweiterungsfunktionen sind praktisch, um mit Rändern umzugehen:

Legt die Ränder aller Achsen in den ViewGroup's fest MarginLayoutParams. (Die Bemaßung muss in Pixel angegeben werden. Weitere Informationen finden Sie im letzten Abschnitt, wenn Sie mit dp arbeiten möchten.)

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

Aktualisiert die Ränder in den 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)

Aktualisiert die relativen Ränder in den ViewGroup's MarginLayoutParams(Start / Ende statt links / rechts).

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)

Die folgenden Erweiterungseigenschaften sind praktisch, um die aktuellen Ränder abzurufen:

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
  • Verwenden dpstatt px:

Wenn Sie dpstattdessen mit (dichteunabhängigen Pixeln) arbeiten möchten px, müssen Sie diese zuerst konvertieren. Mit der folgenden Erweiterungseigenschaft können Sie dies problemlos tun:

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

Dann können Sie die vorherigen Erweiterungsfunktionen wie folgt aufrufen:

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

Alte Antwort:

In Kotlin können Sie eine Erweiterungsfunktion wie folgt deklarieren:

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

Dann können Sie es so nennen:

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

Oder:

myView2.setMargins(topMarginDp = 8) 
David Miguel
quelle