Gdzie poszedł dopełnienie podczas ustawiania tła do rysowania?

86

Mam ten problem na moich widokach EditTexti Button, gdzie mam ładne wypełnienie, aby oddzielić je od tekstu, ale kiedy zmienię tło za pomocą setBackgroundDrawablelub setBackgroundResource, wypełnienie jest tracone na zawsze.

Dandre Allison
źródło
2
Ten problem został rozwiązany w systemie Android 4.4 KitKat
Vladimir
2
Na moim Nexusie 5 z 4.4.3 ten problem nadal występuje.
Bianca Daniciuc
1
Uważam, że został naprawiony tylko w Lollipop (5.0)
Aviv Ben Shabat
Miałem ten sam problem z a TextViewi zaakceptowane rozwiązanie poniżej również działało dla tego typu widoku.
Stonz2
Problem z TextViewinterfejsem API 28 (Android 9). Wygląda na to, że nigdy nie został naprawiony.
Sdghasemi

Odpowiedzi:

97

To, co znalazłem, to dodanie łatki 9 jako zasobu tła zresetowania wypełnienia - chociaż co ciekawe, jeśli dodałem kolor lub obraz łatki inny niż 9, tak się nie stało. Rozwiązaniem było zapisanie wartości wypełnienia przed dodaniem tła, a następnie ustawienie ich ponownie.

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
źródło
Dla każdego, kto napotka jakieś problemy przy użyciu tego podejścia, należy wywołać getPadding ... PRZED wywołaniem setBackgroundResource ().
Chris.Zou
Wygląda na to, że w ten sposób nie zachowałbyś wyściółki do rozciągania?
Thuy Trinh
4
Chciałbym wspomnieć, że nie musisz tego robić powyżej API 19 (Kitkat), ponieważ Google rozwiązało ten błąd.
ywwynm
@ywwynm powyżej czy równa się KitKat?
HendraWD
OK, wypróbowałem to sam, nie musimy go używać do API 19 (Kitkat) lub nowszego (> = Kitkat)
HendraWD
14

Udało mi się zawinąć element w inny układ, w tym przypadku plik FrameLayout. Umożliwiło mi to zmianę tła na stronie FrameLayoutbez niszczenia wypełnienia, które znajduje się na zawartym 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" 
     />
...

Inną opcją jest ustawienie go programowo po ustawieniu tła, Drawablejak zasugerowano powyżej. Tylko pamiętaj, aby obliczyć piksele, aby skorygować rozdzielczość urządzenia.

Brudny kalwinista
źródło
12

Miałem ten problem w TextView, więc podklasowałem TextView i utworzyłem metodę Override dla TextView.setBackgroundResource(int resid)metody. Lubię to:

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

W ten sposób uzyskuje wypełnienie elementu przed ustawieniem zasobu, ale w rzeczywistości nie zakłóca oryginalnej funkcjonalności metody, poza zachowaniem wypełnienia.

LukeWaggoner
źródło
9

Nie testowałem tego bardzo dokładnie, ale ta metoda może być przydatna:

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

Użyj tego zamiast view.setBackgroundDrawable (Drawable).

cottonBallPaws
źródło
3
Jeśli widok ma już wypełnienie z jakiejś strony, po wielokrotnym wywołaniu tej funkcji obraz tła przesuwa się na bok, ponieważ zwiększasz dopełnienie widoku o poprzednią wartość
iBog
Tak, jeśli wypełnienie będzie zmieniane kilka razy, wybierz inne podejście. Ewentualnie śledź oryginalne wypełnienie w porównaniu z wyściółką do wyciągania.
cottonBallPaws
2

Wstecznie kompatybilna wersja odpowiedzi 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.
źródło
1

Możesz nadać dopełnienie, używając obrazów 9-poprawkowych i definiując obszar zawartości w rysowanym. Sprawdź to

Możesz także ustawić dopełnienie w swoim układzie z xml lub programowo

xml dopełnianie tagów

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

Możesz spróbować ustawić dopełnienie ręcznie z kodu po wywołaniu metody setBackgroundDrawable, wywołując metodę setPadding w widoku EditText lub Button

achie
źródło
Mam zdefiniowane dopełnienie dla EditText i Button w XML i pokazuje się świetnie, dopóki nie zmienię Drawable, a potem stracę wypełnienie.
Dandre Allison,
Może się to zmienić w zależności od zmian w obszarach zawartości między poprzednimi i nowymi elementami rysunkowymi. Czy próbowałeś zwiększyć wyściółkę i sprawdzić, czy daje jakieś wypełnienie, czy nie.
achie
1
Ok, przepraszam, powinienem był przeczytać całkowicie twoje pytanie. Ponieważ zmieniasz tło rysunkowe, może to oznaczać usunięcie wypełnienia. Nie jestem pewien, czy tak jest. Ale jeśli tak jest, możesz spróbować ustawić dopełnienie ręcznie z kodu po wywołaniu setBackgroundDrawable, wywołując setPadding w EditText lub Button Views
achie
1

Dla zwykłego wyszukiwania,

po prostu dodaj setPadding po setBackgroudDrawable. Kiedy zmienisz swój drawable, musisz ponownie wywołać setPadding.

Lubić:

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

Najprostszym sposobem jest zdefiniowanie dopełnień wewnątrz pliku XML-drawable, który wskazuje na plik-obraz-do-rysowania

Pozdrowienia

Torsten
źródło
1

Moim rozwiązaniem było rozszerzenie widoku (w moim przypadku EditText ) oraz nadpisanie setBackgroundDrawable()i setBackgroundResource()metody:

// 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
źródło
1

Łącząc rozwiązania wszystkich napisałem jedno w Kotlinie:

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)
}
programista Androida
źródło
1

Aby wyjaśnić, co się dzieje:

Właściwie to funkcja. Elementy rysunkowe układu, których możesz użyć jako tła, mogą definiować wypełnienie w następujący sposób:

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

To wypełnienie zostanie ustawione wraz z nowym tłem do rysowania. Gdy nie ma dopełnienia, wartość domyślna to 0.

Więcej informacji z e-maila napisanego przez Romaina Guya: https://www.mail-archive.com/[email protected]/msg09595.html

Achraf Amil
źródło
0

po prostu zmień lib na v7: 22.1.0 w Android Studio, jak ta kompilacja „com.android.support:appcompat-v7:22.1.0”

user3104023
źródło
0

Większość odpowiedzi jest poprawna, ale powinny poprawnie obsługiwać ustawienia w tle.

Najpierw uzyskaj dopełnienie swojego widoku

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

Następnie ustaw tło

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

Następnie ustaw dopełnienie widoku przed zmianą tła

myView.setPadding(padding, padding, padding, padding);
cutiko
źródło
0

Znalazłem inne rozwiązanie. Miałem podobny problem z Buttons. Ostatecznie dodałem:

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

to działało dla mnie. Domyślne wypełnienie jest prawie takie samo.

Salman Santino
źródło
0

W moim przypadku miałem drawable i byłem tak głupi, że nie widziałem, aby dopingi były ustawione na 0 w xml.

Displee
źródło
-1

Tutaj ulepszona wersja zestawu CottonBallPaws setBackgroundAndKeepPadding. Zachowuje to dopełnienie, nawet jeśli wywołujesz metodę wiele razy:

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

Musisz zdefiniować identyfikator zasobu za pomocą values ​​/ ids.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="prev_background_padding" type="id"/>
</resources>
Oliver Jonas
źródło
-1

Używam tego dość łatwo obejść I zdefiniować accentColorw moim style.xmljak poniżej

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

a potem używam jednego z poniższych stylów w moich Buttontagach

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

na przykład :

<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
źródło
Nie ma to związku z pytaniem.
Miha_x64