ช่องว่างภายในจะไปที่ไหนเมื่อตั้งค่าพื้นหลัง Drawable


88

ฉันมีปัญหานี้เกี่ยวกับมุมมองEditTextและButtonมุมมองของฉันซึ่งฉันมีช่องว่างที่ดีเพื่อให้พวกเขาเว้นระยะห่างจากข้อความ แต่เมื่อฉันเปลี่ยนพื้นหลังsetBackgroundDrawableหรือsetBackgroundResourceช่องว่างภายในจะหายไปตลอดกาล


2
ปัญหานี้ได้รับการแก้ไขแล้วใน Android 4.4 KitKat
Vladimir

2
ใน Nexus 5 ของฉันที่มี 4.4.3 ปัญหานี้ยังคงเกิดขึ้น
Bianca Daniciuc

1
ฉันเชื่อว่ามันได้รับการแก้ไขเฉพาะใน Lollipop (5.0)
Aviv Ben Shabat

ฉันมีปัญหาเดียวกันกับ a TextViewและวิธีแก้ปัญหาที่ยอมรับด้านล่างก็ใช้ได้กับมุมมองประเภทนั้นเช่นกัน
Stonz2

มีปัญหาในTextViewAPI 28 (Android 9) เช่นกัน ดูเหมือนไม่เคยแก้ไข
Sdghasemi

คำตอบ:


99

สิ่งที่ฉันพบคือการเพิ่มแพตช์ 9 ตัวเป็นทรัพยากรพื้นหลังรีเซ็ตช่องว่างภายในแม้ว่าฉันจะเพิ่มสีหรือภาพแพทช์ที่ไม่ใช่ 9 แต่ก็ไม่ได้เป็นเช่นนั้น วิธีแก้ปัญหาคือบันทึกค่า padding ก่อนที่จะเพิ่มพื้นหลังแล้วตั้งค่าอีกครั้งในภายหลัง

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

สำหรับใครก็ตามที่ประสบปัญหาในการใช้แนวทางนี้โปรดโทรไปที่ getPadding ... ก่อนเรียกใช้ setBackgroundResource ()
Chris.Zou

ดูเหมือนว่าวิธีนี้จะไม่ทำให้ช่องว่างภายในวาดได้?
Thuy Trinh

4
ฉันขอแจ้งว่าคุณไม่ได้ทำสิ่งนี้เหนือ API 19 (Kitkat) เนื่องจาก Google ได้แก้ไขข้อบกพร่องนี้แล้ว
ywwynm

@ywwynm ข้างบนหรือเท่ากับ kitkat?
HendraWD

ตกลงฉันได้ลองด้วยตัวเองแล้วเราไม่จำเป็นต้องใช้สำหรับ API 19 (Kitkat) หรือสูงกว่า (> = Kitkat)
HendraWD

14

ฉันสามารถรวมองค์ประกอบไว้ในเลย์เอาต์อื่นได้ในกรณีนี้คือ a FrameLayout. สิ่งที่ทำให้ผมเปลี่ยนพื้นหลังบนที่โดยไม่ทำลายช่องว่างภายในซึ่งอยู่บนที่มีอยู่FrameLayoutRelativeLayout

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

อีกทางเลือกหนึ่งคือการตั้งค่าโดยใช้โปรแกรมหลังจากตั้งค่าพื้นหลังDrawableตามที่แนะนำข้างต้น เพียงตรวจสอบให้แน่ใจว่าได้คำนวณพิกเซลให้ถูกต้องสำหรับความละเอียดของอุปกรณ์


12

ฉันมีปัญหานี้ใน TextView ดังนั้นฉันจึงซับคลาส TextView และสร้างเมธอด Override ของTextView.setBackgroundResource(int resid)เมธอด แบบนี้:

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

วิธีนี้จะได้รับช่องว่างภายในของรายการก่อนที่จะตั้งค่าทรัพยากร แต่ไม่ได้ยุ่งกับฟังก์ชันการทำงานดั้งเดิมของวิธีการอื่นนอกจากการเก็บช่องว่าง


9

ยังไม่ได้ทดสอบขั้นสูงนี้อย่างละเอียด แต่วิธีนี้อาจใช้:

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

ใช้สิ่งนี้แทน view.setBackgroundDrawable (Drawable)


3
หากมุมมองมีช่องว่างในบางด้านอยู่แล้วหลังจากเรียกใช้ฟังก์ชันนี้หลายครั้งภาพพื้นหลังจะเลื่อนไปด้านข้างเนื่องจากคุณเพิ่มช่องว่างการดูด้วยค่าก่อนหน้า
iBog

ถ้าจะเปลี่ยนช่องว่างภายในหลาย ๆ ครั้งคุณจะต้องใช้แนวทางอื่น อาจติดตามช่องว่างภายในเดิมเทียบกับช่องว่างภายในที่ดึงได้
cottonBallPaws

2

คำตอบของ 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

คุณสามารถเพิ่มช่องว่างภายในได้โดยใช้ภาพ 9 ภาพและกำหนดพื้นที่เนื้อหาในภาพวาด ตรวจสอบสิ่งนี้

คุณยังสามารถตั้งค่า padding ในเค้าโครงของคุณจาก xml หรือโดยใช้โปรแกรม

xml padding tags

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

คุณสามารถลองตั้งค่าช่องว่างภายในด้วยตนเองจากรหัสหลังจากที่คุณเรียกใช้ setBackgroundDrawable โดยเรียกใช้ setPadding บน EditText หรือ Button Views


ฉันได้กำหนดช่องว่างภายในสำหรับ EditText และ Button ใน XML และแสดงได้ดีมากจนกระทั่งฉันเปลี่ยน Drawable จากนั้นฉันจะสูญเสียช่องว่างภายใน
Dandre Allison

อาจมีการเปลี่ยนแปลงขึ้นอยู่กับการเปลี่ยนแปลงในพื้นที่เนื้อหาระหว่างรายการก่อนหน้าและรายการวาดใหม่ คุณลองเพิ่มช่องว่างภายในและดูว่ามีช่องว่างภายในหรือไม่
achie

1
โอเคขอโทษฉันควรอ่านคำถามของคุณจนหมดแล้ว เนื่องจากคุณกำลังเปลี่ยนพื้นหลังที่วาดได้จึงอาจนำช่องว่างภายในออก ผมไม่แน่ใจว่าเป็นอย่างนั้น แต่ถ้าเป็นเช่นนั้นคุณสามารถลองตั้งค่าช่องว่างภายในด้วยตนเองจากรหัสหลังจากเรียกใช้ setBackgroundDrawable โดยเรียก setPadding บน EditText หรือ Button Views ของคุณ
achie

1

สำหรับผู้ค้นหาทั่วไป

เพียงเพิ่ม setPadding หลัง setBackgroudDrawable เมื่อคุณเปลี่ยน drawable คุณต้องเรียกใช้ setPadding อีกครั้ง

ชอบ:

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

วิธีที่สะอาดที่สุดคือกำหนด paddings ของคุณภายใน xml-drawable ซึ่งชี้ไปที่ไฟล์ drawable-image-file

มหาวิหาร


1

วิธีแก้ปัญหาของฉันคือการขยายมุมมอง (ในกรณีของฉันคือEditText ) และแทนที่setBackgroundDrawable()และsetBackgroundResource()วิธีการ:

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

เมื่อรวมวิธีแก้ปัญหาทั้งหมดฉันเขียนหนึ่งใน 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

เพียงเพื่ออธิบายว่าเกิดอะไรขึ้น:

มันเป็นคุณสมบัติจริงๆ โครงร่างโครงร่างที่คุณอาจใช้เป็นพื้นหลังสามารถกำหนดช่องว่างภายในด้วยวิธีนี้:

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

ช่องว่างภายในนี้จะถูกตั้งค่าพร้อมกับพื้นหลังใหม่ที่วาดได้ เมื่อไม่มีช่องว่างภายในค่าเริ่มต้นคือ 0

ข้อมูลเพิ่มเติมจากอีเมลที่เขียนโดย Romain Guy: https://www.mail-archive.com/android-developers@googlegroups.com/msg09595.html



0

คำตอบส่วนใหญ่ถูกต้อง แต่ควรจัดการกับการตั้งค่าพื้นหลังให้ถูกต้อง

ก่อนอื่นให้หาช่องว่างในมุมมองของคุณ

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

จากนั้นตั้งค่าพื้นหลัง

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

จากนั้นตั้งค่าช่องว่างภายในมุมมองก่อนที่จะเปลี่ยนพื้นหลัง

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

0

ฉันพบทางออกอื่น ฉันประสบปัญหาที่คล้ายกันกับปุ่มต่างๆ ในที่สุดฉันก็เพิ่ม:

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

มันได้ผลสำหรับฉัน ช่องว่างภายในเริ่มต้นเกือบจะเหมือนกัน



-1

นี่คือรุ่นที่ปรับปรุงแล้วของ setBackgroundAndKeepPadding ของ 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.
 */
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);
}

คุณต้องกำหนดรหัสทรัพยากรผ่านค่า / ids.xml:

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

-1

ฉันใช้วิธีแก้ปัญหาที่ค่อนข้างง่ายที่ฉันกำหนดaccentColorในสิ่งที่style.xmlชอบด้านล่าง

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

จากนั้นฉันใช้รูปแบบต่อไปนี้ในButtonแท็กของฉัน

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

ตัวอย่างเช่น :

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

เรื่องนี้ไม่เกี่ยวข้องกับคำถาม
Miha_x64
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.