setBackgroundResource()丢弃我的XML布局属性


70

我有一个视图,它用作的项目ListView。在我的自定义适配器中,我View.setBackgroundResource()根据列表中项目的位置来更改视图的背景。(我在列表中的第一项和最后一项都有单独的资产。)

这样可以按预期设置正确的背景图像,但是它具有讨厌的副作用,即完全忽略了我在视图的XML定义中设置的所有填充。

(如果我在XML中设置了背景可绘制,并且不尝试在运行时在适配器中更改背景,则填充都可以正常工作。)

如何更改背景图像并保留填充?这是一个错误吗?

编辑似乎其他人在这里发现了相同的问题:更改背景是否还会更改LinearLayout的填充?

Answers:


106

我也遇到了这个问题。大概您正在使用可绘制的LayerList资源?那就是我在用的。不幸的是,我没有找到修复它的“真正”方法,这似乎是代码中的错误,但是我没有追逐它。但是,从某种意义上来说,我很幸运,因为我已经正确渲染了视图后才设置了“越野车”背景,因此只需要保存并在设置背景后恢复填充值即可,例如:

  if(condition) {
    int bottom = theView.getPaddingBottom();
    int top = theView.getPaddingTop();
    int right = theView.getPaddingRight();
    int left = theView.getPaddingLeft();
    theView.setBackgroundResource(R.drawable.entry_bg_with_image);
    theView.setPadding(left, top, right, bottom);
  }

编辑:作为替代,您不必使用填充的先前值,也可以使用尺寸值:

  int pad = resources.getDimensionPixelSize(R.dimen.linear_layout_padding);
  theView.setBackgroundResource(R.drawable.entry_bg_with_image);
  theView.setPadding(pad, pad, pad, pad);

治愈,谢谢。在我的情况下,可绘制对象是九补丁PNG。
Graham Borland

3
嗯,确实是。在setBackgroundDrawable()中查看View的代码(j.mp/kxQJIJ)。显然,使用可绘制对象的填充覆盖了填充。但是,看看Drawable资源文档,除了形状之外,什么都没有支持填充,因此这可能就是为什么它会失败的原因。
dmon 2011年

1
看起来罗曼·盖伊(Romain Guy)只是将其关闭为“按预期工作”。在代码中有一条注释可以证明这种行为是正确的,因此它是有意完成的。我想如果它记录在某个地方会更好。
dmon 2011年

16
当我的意思是通过使用setBackgroundResource()仅更改图像的背景资源而不更改任何其他属性时,这绝对不是“按预期方式工作”,我从没想到它会影响元素的填充。
埃拉德·纳瓦

2
罗曼说:“设置图像会重置填充的原因是因为9色块图像可以对填充进行编码。如果丢失,我们会假设填充为0。” 应该是“如果缺少&& is9Patch() ”,恕我直言。
adamdport

11

除了dmon所建议的功能之外,这里还提供了一个函数,您可以将其放入util类中,这样就不必在每次更新资源时都无所顾忌。这实际上只是他的代码包装在一个函数中。

public static void updateBackgroundResourceWithRetainedPadding(View view, int resourceID)
{
    int bottom = view.getPaddingBottom();
    int top = view.getPaddingTop();
    int right = view.getPaddingRight();
    int left = view.getPaddingLeft();
    view.setBackgroundResource(resourceID);
    view.setPadding(left, top, right, bottom);
}

7

这在棒棒糖中固定,所以

public static void setBackgroundResource(@NonNull View view, @DrawableRes int resId) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        int paddingTop = view.getPaddingTop();
        int paddingLeft = view.getPaddingLeft();
        int paddingRight = view.getPaddingRight();
        int paddingBottom = view.getPaddingBottom();
        view.setBackgroundResource(resId);
        view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    } else {
        view.setBackgroundResource(resId);
    }
}

1
不,这不是在棒棒糖中固定的(至少不是在我的股票5.1 Moto G ROM中固定)
Henrique de Sousa

自KitKat以来,此问题已修复,因此检查应为Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
大卫,

还没固定在我的像素2 API 29
DIRTY DAVE

6

我选择使用的另一个解决方案,而不是在dmon提出的代码中获取和设置填充,是不使用填充,而是对内部元素使用边距。

根据您的布局,它实际上可能是相同数量的XML代码,根本不需要任何Java。对我来说,这有点脏,但不如在各处添加Java代码那么脏。


-2

在Monodroid中,如果我将呼叫发布到SetBackgroundResource,则顶部填充和底部填充保持不变

private EditText _etInput

public void Disable()
{
    _etInput.Post(() => {
        _etInput.SetBackgroundResource(Resource.Drawable.input_field_background_disabled);
        _etInput.Clickable = false;
});

但是,左填充会重置为0!?如果未发布,则所有填充都将重置为0。

认为这是一个值得一提的有趣发现...

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.