Dov'è finito il riempimento, quando si imposta lo sfondo Drawable?


86

Ho questo problema sul mio EditTexte Buttondi vista, dove ho una bella imbottitura per loro di spazio lontano dal testo, ma quando cambio lo sfondo con setBackgroundDrawableo setBackgroundResourceche imbottitura è perso per sempre.


2
Questo problema è stato risolto in Android 4.4 KitKat
Vladimir

2
Sul mio Nexus 5 con 4.4.3 questo problema persiste.
Bianca Daniciuc

1
Credo che sia stato risolto solo in Lollipop (5.0)
Aviv Ben Shabat

Avevo lo stesso problema con a TextViewe la soluzione accettata di seguito ha funzionato anche per quel tipo di visualizzazione.
Stonz2

Avere il problema anche su TextViewAPI 28 (Android 9). Sembra che non sia mai stato risolto.
Sdghasemi

Risposte:


97

Quello che ho trovato è stato l'aggiunta di una patch 9 come risorsa in background per ripristinare il riempimento, anche se è interessante notare che se ho aggiunto un'immagine di patch a colori o non 9, non è stato così. La soluzione era salvare i valori di riempimento prima che lo sfondo venisse aggiunto, quindi impostarli di nuovo in seguito.

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

Per chiunque incontri dei problemi usando questo approccio, assicurati di chiamare getPadding ... PRIMA di chiamare setBackgroundResource ().
Chris.Zou

Sembra che in questo modo non manterrebbe l'imbottitura disegnabile?
Thuy Trinh

4
Vorrei menzionare che non devi farlo sopra l'API 19 (Kitkat) poiché Google ha risolto questo bug.
ywwynm

@ywwynm sopra o è uguale a kitkat?
HendraWD

OK, l'ho provato io stesso, non abbiamo bisogno di usarlo per API 19 (Kitkat) o superiore (> = Kitkat)
HendraWD

14

Sono stato in grado di avvolgere l'elemento all'interno di un altro layout, in questo caso, un file FrameLayout. Ciò mi ha permesso di cambiare lo sfondo sul FrameLayoutsenza distruggere l'imbottitura, che è sul contenuto 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" 
     />
...

L'altra opzione è impostarlo a livello di programmazione dopo aver impostato lo sfondo Drawablecome suggerito sopra. Assicurati solo di calcolare i pixel da correggere per la risoluzione del dispositivo.


12

Ho avuto questo problema in un TextView, quindi ho sottoclasse TextView e ho creato un metodo Override del TextView.setBackgroundResource(int resid)metodo. Come questo:

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

In questo modo, ottiene il riempimento dell'elemento prima di impostare la risorsa, ma in realtà non altera la funzionalità originale del metodo, oltre a mantenere il riempimento.


9

Non l'ho testato a fondo, ma questo metodo potrebbe essere utile:

    /**
 * 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);
}

Usa questo invece di view.setBackgroundDrawable (Drawable).


3
Se la visualizzazione ha già il riempimento su un lato, dopo aver chiamato questa funzione più volte, l'immagine di sfondo si sposta sul lato, perché aumenti il ​​riempimento della vista con il valore precedente
iBog

Sì, se l'imbottitura verrà modificata più volte, dovresti adottare un approccio diverso. Possibilmente tenere traccia dell'imbottitura originale rispetto all'imbottitura estraibile.
cottonBallPaws

2

Versione retrocompatibile della risposta di 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);
}

1

Puoi dare un po 'di riempimento usando immagini a 9 patch e definendo l'area del contenuto nel disegnabile. Verificare questo

Puoi anche impostare il riempimento nel layout da xml o in modo programmatico

tag di riempimento xml

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

Puoi provare a impostare manualmente il riempimento dal codice dopo aver chiamato setBackgroundDrawable chiamando setPadding nelle visualizzazioni EditText o Button


Ho un riempimento definito per EditText e Button in XML, e si vede benissimo, finché non cambio il Drawable, quindi perdo il padding.
Dandre Allison

Può cambiare a seconda del cambiamento nelle aree del contenuto tra i tuoi disegni precedenti e quelli nuovi. Hai provato ad aumentare l'imbottitura e vedere se dà qualche imbottitura o meno.
Achie

1
Ok scusa avrei dovuto leggere completamente la tua domanda. Dato che stai modificando lo sfondo drawable, potrebbe essere la rimozione del padding. Non sono sicuro che sia così. Ma se questo è il caso, puoi provare a impostare manualmente il riempimento dal codice dopo aver chiamato setBackgroundDrawable chiamando setPadding su EditText o Button Views
Raggiungi il

1

Per un ricercatore comune,

basta aggiungere setPadding dopo setBackgroudDrawable. Quando cambi il tuo drawable, devi chiamare di nuovo setPadding.

Piace:

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

Il modo più pulito è definire i tuoi padding all'interno di un xml-drawable che punta al file di immagine drawable

Greatings


1

La mia soluzione era estendere la vista (nel mio caso un EditText ) e sovrascrivere setBackgroundDrawable()e setBackgroundResource()metodi:

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

1

Combinando le soluzioni di tutte, ne ho scritta una su 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)
}

1

Solo per spiegare cosa sta succedendo:

In realtà è una caratteristica. I drawable del layout che potresti usare come sfondi possono definire un riempimento in questo modo:

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

Questa imbottitura verrà impostata insieme al nuovo sfondo disegnabile. Quando non c'è riempimento, il valore predefinito è 0.

Maggiori informazioni da un'e-mail scritta da Romain Guy: https://www.mail-archive.com/android-developers@googlegroups.com/msg09595.html


0

basta cambiare lib in v7: 22.1.0 in Android Studio come questa compilazione 'com.android.support:appcompat-v7:22.1.0'


0

La maggior parte delle risposte sono corrette ma dovrebbero gestire correttamente l'impostazione dello sfondo.

Per prima cosa ottieni il riempimento della tua vista

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

Quindi imposta lo sfondo

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

Quindi imposta il riempimento della vista prima del cambio di sfondo

myView.setPadding(padding, padding, padding, padding);

0

Ho trovato un'altra soluzione. Stavo affrontando il problema simile con i pulsanti. Alla fine, ho aggiunto:

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

ha funzionato per me. Il riempimento predefinito è quasi lo stesso.


0

Nel mio caso avevo un drawable ed ero così stupido che non ho visto che i padding erano tutti impostati su 0 nell'xml.


-1

Ecco una versione migliorata di setBackgroundAndKeepPadding di cottonBallPaws. Ciò mantiene il riempimento anche se chiami il metodo più volte:

/**
 * 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);
}

Devi definire un ID risorsa tramite values ​​/ ids.xml:

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

-1

Uso questa soluzione alternativa piuttosto semplice che definisco a accentColornel mio style.xmlsimile di seguito

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

e poi utilizzo uno dei seguenti stili nei miei Buttontag

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

per esempio :

<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" />

Questo non è correlato alla domanda.
Miha_x64
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.