设置背景Drawable时,填充会去哪里?


86

我对我的这个问题EditTextButton意见,在这里我对他们一个很好的填充空间从文了,但是当我改变的背景,setBackgroundDrawable或者setBackgroundResource说填补处理永远失去了。


2
这个问题是固定在Android 4.4的奇巧
弗拉基米尔

2
在带有4.4.3的Nexus 5上,此问题仍在发生。
比安卡·丹尼库克

1
我相信这是在棒棒堂只有固定的(5.0)
特拉维夫奔Shabat

我在使用时遇到了同样的问题,TextView下面接受的解决方案也适用于这种视图。
Stonz2 '16

TextViewAPI 28(Android 9)上也存在问题。看起来它从未修复过。
Sdghasemi

Answers:


97

我发现添加9补丁作为背景资源重置了填充-尽管有趣的是,如果我添加了彩色或非9补丁图像,则没有。解决方案是在添加背景之前保存填充值,然后再设置它们。

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

看来这种方式不会保留可绘制的填充?
Thuy Trinh 2014年

4
我想提及的是,由于Google已经解决了该错误,因此您不必在API 19(Kitkat)之上执行此操作。
ywwynm

@ywwynm等于还是等于kitkat?
HendraWD

好的,我自己尝试过,我们不需要将其用于API 19(Kitkat)或更高版本(> = Kitkat)
HendraWD

14

我能够将元素包装在另一个布局中,在本例中为FrameLayout。这样一来,我可以更改的背景,而FrameLayout不会破坏包含在其中的填充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" 
     />
...

另一个选项是Drawable按照上述建议设置背景后,以​​编程方式进行设置。只需确保计算像素以校正设备的分辨率即可。


12

我在TextView中遇到了这个问题,所以我将TextView子类化,并对该TextView.setBackgroundResource(int resid)方法进行了Override方法。像这样:

@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 2013年

是的,如果填充将要多次更改,则可能需要采用其他方法。可能会跟踪原始填充和可绘制填充。
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色块图像并在可绘制对象中定义内容区域来进行填充。 检查一下

您还可以通过xml或以编程方式在布局中设置填充

xml填充标签

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

您可以在调用setBackgroundDrawable之后尝试通过代码手动设置填充,方法是在EditText或Button视图上调用setPadding


我已经为XML中的EditText和Button定义了填充,它显示的很好,直到更改Drawable,然后我才丢失了填充。
Dandre Allison'4

它可能会有所不同,具体取决于先前和新绘制对象之间内容区域的变化。您是否尝试增加填充并查看是否提供任何填充。
achie 2012年

1
好的,抱歉,我应该已经完整阅读了您的问题。由于您正在更改backgrounddrawable,因此可能正在删除填充。我不确定情况是否如此。但是,如果是这样的话,你可以尝试从代码中手动设置填充OU致电setBackgroundDrawable致电您的EditText或按钮查看setPadding后
的政绩

1

对于普通搜索者,

只需在setBackgroudDrawable之后添加setPadding。更改可绘制对象时,必须再次调用setPadding。

喜欢:

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

最干净的方法是在xml-drawable中定义填充,该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

只需将android studio中的lib更改为v7:22.1.0,就像这样编译'com.android.support:appcompat-v7:22.1.0'


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

我找到了另一个解决方案。我正面临着Buttons的类似问题。最终,我添加了:

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

它为我工作。默认填充几乎相同。


0

就我而言,我有一个可绘制对象,但它是如此愚蠢,以至于我看不到xml中的填充都设置为0。


-1

这里是cottonBallPaws的setBackgroundAndKeepPadding的改进版本。即使您多次调用该方法,也可以保持填充:

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

您需要通过values / ids.xml定义资源ID:

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

-1

我使用这个非常简单的解决方法,accentColorstyle.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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.