Phần đệm sẽ đi đâu, khi thiết lập nền có thể vẽ?


86

Tôi gặp sự cố này trên các chế độ xem EditTextvà của mình Button, nơi tôi có một phần đệm đẹp để chúng có thể cách xa văn bản, nhưng khi tôi thay đổi nền bằng setBackgroundDrawablehoặc phần setBackgroundResourceđệm đó sẽ bị mất vĩnh viễn.


2
Sự cố này đã được khắc phục trong Android 4.4 KitKat
Vladimir

2
Trên Nexus 5 với 4.4.3 của tôi, sự cố này vẫn xảy ra.
Bianca Daniciuc,

1
Tôi tin rằng nó chỉ được cố định trong Lollipop (5.0)
Aviv Ben Shabat

Tôi đang gặp vấn đề tương tự với a TextViewvà giải pháp được chấp nhận bên dưới cũng hoạt động cho kiểu xem đó.
Stonz2

Cũng gặp sự cố TextViewtrên API 28 (Android 9). Có vẻ như nó chưa bao giờ được sửa.
Sdghasemi

Câu trả lời:


97

Những gì tôi tìm thấy là thêm bản vá 9 làm tài nguyên nền đặt lại đệm - mặc dù thú vị là nếu tôi thêm màu hoặc hình ảnh không phải của bản vá 9, thì không. Giải pháp là lưu các giá trị đệm trước khi nền được thêm vào, rồi đặt lại sau đó.

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

Đối với bất kỳ ai gặp phải một số vấn đề khi sử dụng cách tiếp cận này, hãy nhớ gọi getPadding ... TRƯỚC KHI gọi setBackgroundResource ().
Chris.Zou,

Có vẻ như cách này sẽ không giữ được đệm có thể kéo được?
Thuy Trinh

4
Tôi muốn đề cập rằng bạn không phải làm điều này ở trên API 19 (Kitkat) vì Google đã giải quyết được lỗi này.
ywwynm

@ywwynm trên hay bằng kitkat?
HendraWD

OK, tôi đã thử nó bản thân mình, chúng ta không cần phải sử dụng nó cho API 19 (Kitkat) hoặc cao hơn (> = Kitkat)
HendraWD

14

Tôi đã có thể bọc phần tử bên trong một bố cục khác, trong trường hợp này, a FrameLayout. Điều đó cho phép tôi thay đổi nền trên FrameLayoutmà không phá hủy phần đệm nằm trên phần chứa 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" 
     />
...

Tùy chọn khác là đặt nó theo chương trình sau khi đặt nền Drawablenhư đề xuất ở trên. Chỉ cần đảm bảo tính toán các điểm ảnh để điều chỉnh độ phân giải của thiết bị.


12

Tôi gặp sự cố này trong TextView, vì vậy tôi đã phân lớp TextView và tạo phương thức Ghi đè của TextView.setBackgroundResource(int resid)phương thức. Như thế này:

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

Bằng cách này, nó nhận được phần đệm của mục trước khi nó đặt tài nguyên, nhưng không thực sự gây rối với chức năng ban đầu của phương thức, ngoài việc giữ phần đệm.


9

Chưa kiểm tra kỹ lưỡng điều này, nhưng phương pháp này có thể được sử dụng:

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

Sử dụng cái này thay vì view.setBackgroundDrawable (Có thể vẽ).


3
Nếu như quan điểm đã có đệm trên một số mặt, sau khi gọi hàm này nhiều lần, di chuyển hình nền sang một bên, bởi vì bạn increment xem đệm với giá trị trước đó
iBog

Đúng vậy nếu phần đệm sẽ được thay đổi nhiều lần, bạn muốn thực hiện một cách tiếp cận khác. Có thể theo dõi phần đệm ban đầu so với phần đệm có thể kéo được.
cottonBallPaws

2

Phiên bản tương thích ngược của câu trả lời của 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

Bạn có thể đưa ra một số phần đệm bằng cách sử dụng hình ảnh 9 bản vá và xác định khu vực nội dung trong phần có thể vẽ. Kiểm tra điều này

Bạn cũng có thể đặt phần đệm trong bố cục của mình từ xml hoặc theo chương trình

thẻ đệm xml

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

Bạn có thể thử đặt đệm theo cách thủ công từ mã sau khi bạn gọi setBackgroundDrawable bằng cách gọi setPadding trên EditText hoặc Chế độ xem nút của bạn


Tôi đã định nghĩa phần đệm cho EditText và Button trong XML, và nó hiển thị rất tốt, cho đến khi tôi thay đổi Drawable, thì tôi mất phần đệm.
Dandre Allison

Nó có thể thay đổi tùy thuộc vào sự thay đổi trong các khu vực nội dung giữa các ngăn kéo trước đó và mới của bạn. Bạn đã thử tăng đệm và xem nó có tạo ra đệm nào hay không.
achie

1
Ok, xin lỗi, tôi nên đọc hết câu hỏi của bạn. Vì bạn đang thay đổi nền có thể rút được, nó có thể đang xóa phần đệm. Tôi không chắc rằng đó là trường hợp. Nhưng nếu đó là trường hợp bạn có thể thử thiết lập padding bằng tay từ các mã sau ou gọi setBackgroundDrawable bằng cách gọi setPadding trên EditText hoặc nút của bạn Download
achie

1

Đối với người tìm kiếm thông thường,

chỉ cần thêm setPadding sau setBackgroudDrawable. Khi bạn thay đổi có thể vẽ, bạn phải gọi lại setPadding.

Giống:

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

Cách rõ ràng nhất là xác định các phần đệm của bạn bên trong một tệp có thể kéo xml trỏ đến tệp hình ảnh có thể vẽ

Mỡ bôi trơn


1

Giải pháp của tôi là mở rộng chế độ xem (trong trường hợp của tôi là EditText ) và ghi đè setBackgroundDrawable()setBackgroundResource()các phương pháp:

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

Kết hợp các giải pháp của tất cả, tôi đã viết một giải pháp trong 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

Chỉ để giải thích những gì đang xảy ra:

Nó thực sự là một tính năng. Bố cục có thể vẽ mà bạn có thể sử dụng làm nền có thể xác định vùng đệm theo cách này:

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

Phần đệm này sẽ được đặt cùng với nền có thể vẽ mới. Khi không có phần đệm, giá trị mặc định là 0.

Thông tin thêm từ email do Romain Guy viết: https://www.mail-archive.com/android-developers@googlegroups.com/msg09595.html


0

chỉ cần thay đổi lib thành v7: 22.1.0 trong android studio như biên dịch này 'com.android.support:appcompat-v7:22.1.0'


0

Hầu hết các câu trả lời đều đúng nhưng phải xử lý cài đặt nền một cách chính xác.

Đầu tiên hãy lấy phần đệm của chế độ xem của bạn

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

Sau đó đặt nền

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

Sau đó đặt vùng đệm cho chế độ xem trước khi thay đổi nền

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

0

Tôi đã tìm thấy một giải pháp khác. Tôi đang đối mặt với vấn đề tương tự với Buttons. Cuối cùng, tôi đã thêm:

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

nó đã làm việc cho tôi. Phần đệm mặc định gần như giống nhau.


0

Trong trường hợp của tôi, tôi có một drawable và thật ngu ngốc khi tôi không thấy các paddings được đặt thành 0 trong xml.


-1

Đây là phiên bản cải tiến của setBackgroundAndKeepPadding của cottonBallPaws. Điều này duy trì phần đệm ngay cả khi bạn gọi phương thức nhiều lần:

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

Bạn cần xác định id tài nguyên thông qua giá trị / ids.xml:

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

-1

Tôi sử dụng này khá dễ dàng workaround tôi xác định một accentColortrong tôi style.xmlnhư dưới đây

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

và sau đó tôi sử dụng một trong các kiểu sau trong Buttonthẻ của mình

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

ví dụ :

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

Điều này không liên quan đến câu hỏi.
Miha_x64
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.