Wohin ging das Auffüllen, wenn der Hintergrund Drawable eingestellt wurde?

86

Ich habe dieses Problem in meinen Ansichten EditTextund ButtonAnsichten, in denen ich eine schöne Polsterung habe, damit sie vom Text entfernt bleiben , aber wenn ich den Hintergrund mit ändere setBackgroundDrawableoder setBackgroundResourcediese Polsterung für immer verloren geht.

Dandre Allison
quelle
2
Dieses Problem wurde in Android 4.4 KitKat
Vladimir
2
Auf meinem Nexus 5 mit 4.4.3 tritt dieses Problem immer noch auf.
Bianca Daniciuc
1
Ich glaube, es wurde nur in Lollipop (5.0)
Aviv Ben Shabat
Ich hatte das gleiche Problem mit a TextViewund die unten akzeptierte Lösung funktionierte auch für diese Art von Ansicht.
Stonz2
Das Problem tritt auch auf einer TextViewAPI 28 (Android 9) auf. Sieht so aus, als wäre es nie behoben worden.
Sdghasemi

Antworten:

97

Was ich fand, war das Hinzufügen eines 9-Patches als Hintergrundressource, um das Auffüllen zurückzusetzen - obwohl es interessanterweise nicht so war, wenn ich ein Farb- oder Nicht-9-Patch-Bild hinzufügte. Die Lösung bestand darin, die Füllwerte zu speichern, bevor der Hintergrund hinzugefügt wird, und sie anschließend erneut festzulegen.

private EditText value = (EditText) findViewById(R.id.value);

int pL = value.getPaddingLeft();
int pT = value.getPaddingTop();
int pR = value.getPaddingRight();
int pB = value.getPaddingBottom();

value.setBackgroundResource(R.drawable.bkg);
value.setPadding(pL, pT, pR, pB);
Matt McMinn
quelle
Wenn Sie bei diesem Ansatz auf Probleme stoßen, rufen Sie getPadding ... auf, BEVOR Sie setBackgroundResource () aufrufen.
Chris.Zou
Es scheint, dass auf diese Weise keine ziehbare Polsterung erhalten bleibt?
Thuy Trinh
4
Ich möchte erwähnen, dass Sie dies über API 19 (Kitkat) nicht tun müssen, da Google diesen Fehler behoben hat.
Ywwynm
@ywwynm oben oder gleich Kitkat?
HendraWD
OK, ich habe es selbst versucht, wir müssen es nicht für API 19 (Kitkat) oder höher (> = Kitkat) verwenden
HendraWD
14

Ich konnte das Element in ein anderes Layout einbinden, in diesem Fall a FrameLayout. Dadurch konnte ich den Hintergrund auf dem ändern, FrameLayoutohne die Polsterung zu zerstören, die sich auf dem enthaltenen befindet RelativeLayout.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/commentCell"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:background="@drawable/comment_cell_bg_single" >

    <RelativeLayout android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:padding="20dp" >

    <ImageView android:id="@+id/sourcePic"
               android:layout_height="75dp"
               android:layout_width="75dp"
               android:padding="5dp"
               android:background="@drawable/photoframe" 
     />
...

Die andere Möglichkeit besteht darin, es programmgesteuert einzustellen, nachdem der Hintergrund Drawablewie oben vorgeschlagen eingestellt wurde. Stellen Sie einfach sicher, dass Sie die Pixel berechnen, um die Auflösung des Geräts zu korrigieren.

Der schmutzige Calvinist
quelle
11

Ich hatte dieses Problem in einer TextView, also habe ich TextView untergeordnet und eine Override-Methode für die TextView.setBackgroundResource(int resid)Methode erstellt. So was:

@Override
public void setBackgroundResource(int resid) {
    int pl = getPaddingLeft();
    int pt = getPaddingTop();
    int pr = getPaddingRight();
    int pb = getPaddingBottom();

    super.setBackgroundResource(resid);

    this.setPadding(pl, pt, pr, pb);
}

Auf diese Weise wird das Auffüllen des Elements abgerufen, bevor die Ressource festgelegt wird, es wird jedoch nicht die ursprüngliche Funktionalität der Methode beeinträchtigt, außer dass das Auffüllen beibehalten wird.

LukeWaggoner
quelle
9

Ich habe das noch nicht sehr gründlich getestet, aber diese Methode könnte von Nutzen sein:

    /**
 * Sets the background for a view while preserving its current padding. If the background drawable
 * has its own padding, that padding will be added to the current padding.
 * 
 * @param view View to receive the new background.
 * @param backgroundDrawable Drawable to set as new background.
 */
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);
    int top = view.getPaddingTop() + drawablePadding.top;
    int left = view.getPaddingLeft() + drawablePadding.left;
    int right = view.getPaddingRight() + drawablePadding.right;
    int bottom = view.getPaddingBottom() + drawablePadding.bottom;

    view.setBackgroundDrawable(backgroundDrawable);
    view.setPadding(left, top, right, bottom);
}

Verwenden Sie dies anstelle von view.setBackgroundDrawable (Drawable).

CottonBallPaws
quelle
3
Wenn die Ansicht auf einer Seite bereits eine Auffüllung aufweist, wird das Hintergrundbild nach mehrmaligem Aufrufen dieser Funktion zur Seite verschoben, da Sie die Auffüllung der Ansicht mit dem vorherigen Wert
erhöhen
Ja, wenn die Polsterung mehrmals geändert werden soll, möchten Sie einen anderen Ansatz wählen. Verfolgen Sie möglicherweise die ursprüngliche Polsterung im Vergleich zur ziehbaren Polsterung.
CottonBallPaws
2

Abwärtskompatible Version der Antwort von CottonBallPaws

/** 
  * Sets the background for a view while preserving its current     padding. If the background drawable 
  * has its own padding, that padding will be added to the current padding. 
 *  
 * @param view View to receive the new background. 
 * @param backgroundDrawable Drawable to set as new background. 
 */ 
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@SuppressWarnings("deprecation")
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);
    int top = view.getPaddingTop() + drawablePadding.top;
    int left = view.getPaddingLeft() + drawablePadding.left;
    int right = view.getPaddingRight() + drawablePadding.right;
    int bottom = view.getPaddingBottom() + drawablePadding.bottom;

    int sdk = android.os.Build.VERSION.SDK_INT;
    if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        view.setBackgroundDrawable(backgroundDrawable);
    } else {
        view.setBackground(backgroundDrawable);
    }
    view.setPadding(left, top, right, bottom);
}
Andrew G.
quelle
1

Sie können einige Auffüllungen vornehmen, indem Sie 9-Patch-Bilder verwenden und den Inhaltsbereich im Zeichenbildschirm definieren. Überprüfen Sie dies

Sie können die Auffüllung in Ihrem Layout auch über XML oder programmgesteuert festlegen

XML-Padding-Tags

android:padding
android:paddingLeft
android:paddingRight
android:paddingTop
android:paddingBottom

Sie können versuchen, die Auffüllung manuell über den Code festzulegen, nachdem Sie setBackgroundDrawable aufgerufen haben, indem Sie setPadding in Ihrer EditText- oder Schaltflächenansicht aufrufen

erreichen
quelle
Ich habe das Auffüllen für den EditText und die Schaltfläche in XML definiert und es zeigt sich großartig, bis ich das Drawable ändere und dann das Auffüllen verliere.
Dandre Allison
Dies kann sich abhängig von der Änderung der Inhaltsbereiche zwischen Ihren vorherigen und neuen Zeichen ändern. Haben Sie versucht, die Polsterung zu erhöhen und festzustellen, ob eine Polsterung vorliegt oder nicht?
Erreichen Sie den
1
Ok, tut mir leid, ich hätte deine Frage vollständig lesen sollen. Da Sie die Hintergrundzeichnung ändern, wird möglicherweise die Polsterung entfernt. Ich bin mir nicht sicher, ob dies der Fall ist. Wenn dies jedoch der Fall ist, können Sie versuchen, die Auffüllung manuell über den Code festzulegen, nachdem Sie setBackgroundDrawable aufgerufen haben, indem Sie setPadding in Ihrer EditText- oder Schaltflächenansicht aufrufen
Sie den
1

Für gewöhnliche Sucher,

Fügen Sie einfach setPadding nach setBackgroudDrawable hinzu. Wenn Sie Ihr Drawable ändern, müssen Sie setPadding erneut aufrufen.

Mögen:

view.setBackgroundDrawable(backgroundDrawable);
view.setPadding(x, x, x, x);

Am saubersten ist es, Ihre Auffüllungen in einer XML-Zeichendatei zu definieren, die auf die Zeichenbilddatei verweist

Greatings

Torsten
quelle
1

Meine Lösung bestand darin, die Ansicht zu erweitern (in meinem Fall eine EditText ) zu erweitern und zu überschreiben setBackgroundDrawable()und setBackgroundResource()Methoden:

// Stores padding to avoid padding removed on background change issue
public void storePadding(){
    mPaddingLeft = getPaddingLeft();
    mPaddingBottom = getPaddingTop();
    mPaddingRight = getPaddingRight();
    mPaddingTop = getPaddingBottom();
}

// Restores padding to avoid padding removed on background change issue
private void restorePadding() {
    this.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
}

@Override
public void setBackgroundResource(@DrawableRes int resId) {
    storePadding();
    super.setBackgroundResource(resId);
    restorePadding();
}

@Override
public void setBackgroundDrawable(Drawable background) {
    storePadding();
    super.setBackgroundDrawable(background);
    restorePadding();
}
Juan José Melero Gómez
quelle
1

Ich kombinierte die Lösungen aller und schrieb eine in Kotlin:

fun View.setViewBackgroundWithoutResettingPadding(@DrawableRes backgroundResId: Int) {
    val paddingBottom = this.paddingBottom
    val paddingStart = ViewCompat.getPaddingStart(this)
    val paddingEnd = ViewCompat.getPaddingEnd(this)
    val paddingTop = this.paddingTop
    setBackgroundResource(backgroundResId)
    ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}

fun View.setViewBackgroundWithoutResettingPadding(background: Drawable?) {
    val paddingBottom = this.paddingBottom
    val paddingStart = ViewCompat.getPaddingStart(this)
    val paddingEnd = ViewCompat.getPaddingEnd(this)
    val paddingTop = this.paddingTop
    ViewCompat.setBackground(this, background)
    ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}
Android-Entwickler
quelle
1

Nur um zu erklären, was passiert:

Es ist eigentlich eine Funktion. Layout-Zeichen, die Sie als Hintergrund verwenden können, können eine Auffüllung folgendermaßen definieren:

<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:paddingRight="8dp"
    >
    ...
</layer-list>

Diese Polsterung wird zusammen mit dem neuen zeichnbaren Hintergrund festgelegt. Wenn keine Auffüllung vorhanden ist, ist der Standardwert 0.

Weitere Informationen aus einer E-Mail von Romain Guy: https://www.mail-archive.com/[email protected]/msg09595.html

Achraf Amil
quelle
0

ändere lib in v7: 22.1.0 in android studio wie folgt kompiliere 'com.android.support:appcompat-v7:22.1.0'

user3104023
quelle
0

Die meisten Antworten sind korrekt, sollten jedoch die Hintergrundeinstellung korrekt verarbeiten.

Holen Sie sich zuerst die Auffüllung Ihrer Ansicht

//Here my view has the same padding in all directions so I need to get just 1 padding
int padding = myView.getPaddingTop();

Stellen Sie dann den Hintergrund ein

//If your are supporting lower OS versions make sure to verify the version
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
    //getDrawable was deprecated so use ContextCompat                            
    myView.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
} else {
    myView.setBackground(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
}

Stellen Sie dann die Auffüllung ein, die die Ansicht vor dem Hintergrundwechsel hatte

myView.setPadding(padding, padding, padding, padding);
Cutiko
quelle
0

Ich habe eine andere Lösung gefunden. Ich hatte ein ähnliches Problem mit Buttons. Schließlich fügte ich hinzu:

android:scaleX= "0.85"
android:scaleY= "0.85"

es hat bei mir funktioniert. Die Standardauffüllung ist fast gleich.

Salman Santino
quelle
0

In meinem Fall hatte ich ein Drawable und war so dumm, dass ich nicht sah, dass die Auffüllungen in der XML alle auf 0 gesetzt waren.

Displee
quelle
-1

Hier eine verbesserte Version von CottonBallPaws 'setBackgroundAndKeepPadding. Dadurch bleibt die Auffüllung erhalten, auch wenn Sie die Methode mehrmals aufrufen:

/**
 * Sets the background for a view while preserving its current padding. If the background drawable
 * has its own padding, that padding will be added to the current padding.
 */
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {

    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);

    // Add background padding to view padding and subtract any previous background padding
    Rect prevBackgroundPadding = (Rect) view.getTag(R.id.prev_background_padding);
    int left = view.getPaddingLeft() + drawablePadding.left -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.left);
    int top = view.getPaddingTop() + drawablePadding.top -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.top);
    int right = view.getPaddingRight() + drawablePadding.right -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.right);
    int bottom = view.getPaddingBottom() + drawablePadding.bottom -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.bottom);
    view.setTag(R.id.prev_background_padding, drawablePadding);

    view.setBackgroundDrawable(backgroundDrawable);
    view.setPadding(left, top, right, bottom);
}

Sie müssen eine Ressourcen-ID über values ​​/ ids.xml definieren:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="prev_background_padding" type="id"/>
</resources>
Oliver Jonas
quelle
-1

Ich benutze diese ziemlich einfache Problemumgehung, die ich unten accentColorin meinem style.xmlLike definiere

<item name="colorAccent">#0288D1</item>

und dann verwende ich einen der folgenden Stile in meinen ButtonTags

style="@style/Base.Widget.AppCompat.Button.Colored"
style="@style/Base.Widget.AppCompat.Button.Small"

zum Beispiel :

<Button
    android:id="@+id/btnLink"
    style="@style/Base.Widget.AppCompat.Button.Colored"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/tvDescription"
    android:textColor="@color/textColorPrimary"
    android:text="Visit Website" />

<Button
    android:id="@+id/btnSave"
    style="@style/Base.Widget.AppCompat.Button.Small"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/tvDescription"
    android:layout_toRightOf="@id/btnLink"
    android:textColor="@color/textColorPrimaryInverse"
    android:text="Save" />
Anudeep Samaiya
quelle
Dies hängt nicht mit der Frage zusammen.
Miha_x64