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.


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

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.


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.


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


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

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


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


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

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

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/android-developers@googlegroups.com/msg09595.html


0

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


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

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.


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.


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

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

Nie ma to związku z pytaniem.
Miha_x64
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.