Kemana perginya padding, saat menyetel background Drawable?

88

Saya memiliki masalah ini pada pandangan EditTextdan saya Button, di mana saya memiliki padding yang bagus untuk mereka menjauh dari teks, tetapi ketika saya mengubah latar belakang dengan setBackgroundDrawableatau setBackgroundResourcepadding itu hilang selamanya.

Dandre Allison
sumber
2
Masalah ini telah diperbaiki di Android 4.4 KitKat
Vladimir
2
Di Nexus 5 saya dengan 4.4.3 masalah ini masih terjadi.
Bianca Daniciuc
1
Saya yakin itu diperbaiki hanya di Lollipop (5.0)
Aviv Ben Shabat
Saya mengalami masalah yang sama dengan a TextViewdan solusi yang diterima di bawah ini juga berfungsi untuk jenis tampilan tersebut.
Stonz2
Memiliki masalah di TextViewAPI 28 (Android 9) juga. Sepertinya itu tidak pernah diperbaiki.
Sdghasemi

Jawaban:

99

Apa yang saya temukan adalah menambahkan patch 9 sebagai sumber daya latar belakang mengatur ulang padding - meskipun menariknya jika saya menambahkan warna, atau gambar patch non-9, ternyata tidak. Solusinya adalah menyimpan nilai padding sebelum background ditambahkan, lalu mengaturnya lagi setelahnya.

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
sumber
Bagi siapa pun yang mengalami masalah saat menggunakan pendekatan ini, pastikan untuk memanggil getPadding ... SEBELUM memanggil setBackgroundResource ().
Chris.Zou
Sepertinya cara ini tidak akan mempertahankan padding yang dapat digambar?
Thuy Trinh
4
Saya ingin menyebutkan bahwa Anda tidak perlu melakukan ini di atas API 19 (Kitkat) karena Google telah memecahkan bug ini.
ywwynm
@ywwynm di atas atau sama dengan kitkat?
HendraWD
Oke, saya sudah mencobanya sendiri, kita tidak perlu menggunakannya untuk API 19 (Kitkat) atau lebih tinggi (> = Kitkat)
HendraWD
14

Saya bisa membungkus elemen di dalam layout lain, dalam hal ini, a FrameLayout. Itu memungkinkan saya untuk mengubah latar belakang FrameLayouttanpa merusak padding, yang ada di dalamnya 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" 
     />
...

Pilihan lainnya adalah mengaturnya secara terprogram setelah mengatur latar belakang Drawableseperti yang disarankan di atas. Pastikan untuk menghitung piksel untuk mengoreksi resolusi perangkat.

Calvinis Kotor
sumber
12

Saya mengalami masalah ini dalam TextView, jadi saya membuat subclass TextView dan membuat metode Override dari TextView.setBackgroundResource(int resid)metode tersebut. Seperti ini:

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

Dengan cara ini, ia mendapatkan padding item sebelum ia menyetel sumber daya, tetapi tidak benar-benar mengacaukan fungsionalitas asli dari metode tersebut, selain mempertahankan padding.

LukeWaggoner
sumber
9

Belum menguji ini dengan sangat teliti, tetapi metode ini mungkin berguna:

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

Gunakan ini sebagai ganti view.setBackgroundDrawable (Drawable).

cottonBallPaws
sumber
3
Jika tampilan sudah memiliki padding di beberapa sisi, setelah memanggil fungsi ini beberapa kali, gambar latar belakang akan berpindah ke samping, karena Anda menambah padding tampilan dengan nilai sebelumnya
iBog
Ya, jika padding akan diubah beberapa kali, Anda ingin mengambil pendekatan yang berbeda. Mungkin melacak padding asli versus padding drawable.
cottonBallPaws
2

Versi jawaban cottonBallPaws yang kompatibel dengan versi sebelumnya

/** 
  * 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
sumber
1

Anda bisa memberi beberapa padding dengan menggunakan gambar 9-patch dan menentukan area konten di drawable. Periksa ini

Anda juga dapat menyetel padding dalam tata letak Anda dari xml atau secara terprogram

xml tag padding

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

Anda dapat mencoba menyetel padding secara manual dari kode setelah Anda memanggil setBackgroundDrawable dengan memanggil setPadding pada EditText atau Button Views

mencapai
sumber
Saya memiliki padding yang ditentukan untuk EditText dan Button dalam XML, dan itu menunjukkan hebat, sampai saya mengubah Drawable, kemudian saya kehilangan paddingnya.
Dandre Allison
Ini mungkin berubah tergantung pada perubahan di area konten antara drawable Anda sebelumnya dan baru. Apakah Anda mencoba menambah bantalan dan melihat apakah ada bantalan atau tidak.
mencapai
1
Ok maaf saya harus membaca pertanyaan Anda sepenuhnya. Karena Anda mengubah backgrounddrawable, itu mungkin menghapus padding. Saya tidak yakin itu masalahnya. Tetapi jika itu masalahnya, Anda dapat mencoba mengatur padding secara manual dari kode setelah Anda memanggil setBackgroundDrawable dengan memanggil setPadding pada EditText atau Tampilan Tombol
mencapai
1

Untuk pencari umum,

cukup tambahkan setPadding setelah setBackgroudDrawable. Saat Anda mengubah drawable, Anda harus memanggil setPadding lagi.

Suka:

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

Cara terbersih adalah menentukan paddings Anda di dalam xml-drawable yang mengarah ke file drawable-image

Salam

Torsten
sumber
1

Solusi saya adalah memperluas tampilan (dalam kasus saya sebuah EditText ) dan menimpa setBackgroundDrawable()dan setBackgroundResource()metode:

// 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
sumber
1

Menggabungkan solusi dari semua, saya menulis satu di 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)
}
pengembang android
sumber
1

Hanya untuk menjelaskan apa yang terjadi:

Ini sebenarnya sebuah fitur. Drawable tata letak yang mungkin Anda gunakan sebagai latar belakang dapat menentukan padding dengan cara ini:

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

Padding ini akan disetel bersama dengan latar belakang drawable baru. Jika tidak ada padding, nilai defaultnya adalah 0.

Info lebih lanjut dari email yang ditulis oleh Romain Guy: https://www.mail-archive.com/[email protected]/msg09595.html

Achraf Amil
sumber
0

cukup ubah lib ke v7: 22.1.0 di android studio seperti kompilasi ini 'com.android.support:appcompat-v7:22.1.0'

pengguna3104023
sumber
0

Sebagian besar jawaban benar tetapi harus menangani pengaturan latar belakang dengan benar.

Pertama, dapatkan bantalan pandangan Anda

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

Kemudian atur latar belakang

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

Kemudian atur padding tampilan sebelum latar belakang berubah

myView.setPadding(padding, padding, padding, padding);
cutiko
sumber
0

Saya menemukan solusi lain. Saya menghadapi masalah yang sama dengan Buttons. Akhirnya, saya menambahkan:

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

itu berhasil untuk saya. Padding default hampir sama.

Salman
sumber
0

Dalam kasus saya, saya memiliki drawable dan sangat bodoh sehingga saya tidak melihat paddings semuanya disetel ke 0 di xml.

Tidak senang
sumber
-1

Di sini versi perbaikan dari setBackgroundAndKeepPadding cottonBallPaws. Ini mempertahankan padding meskipun Anda memanggil metode ini beberapa kali:

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

Anda perlu menentukan id sumber daya melalui values ​​/ ids.xml:

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

Saya menggunakan ini cukup mudah atasi saya mendefinisikan accentColordi saya style.xmlseperti di bawah ini

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

dan kemudian saya menggunakan salah satu gaya berikut di Buttontag saya

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

sebagai contoh :

<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
sumber
Ini tidak berhubungan dengan pertanyaan.
Miha_x64