【问题标题】:setBackgroundResource() discards my XML layout attributessetBackgroundResource() 丢弃了我的 XML 布局属性
【发布时间】:2023-12-23 21:33:01
【问题描述】:

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

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

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

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

编辑似乎其他人在这里发现了同样的问题:Does changing the background also change the padding of a LinearLayout?

【问题讨论】:

    标签: android background drawable padding layer-list


    【解决方案1】:

    我也遇到了这个问题。大概您正在使用可绘制的 LayerList 资源?这就是我正在使用的。不幸的是,我没有找到修复它的“真正”方法,这似乎是代码中的一个错误,但我没有追究它。但是,我很幸运,因为在我的视图已经正确渲染之后我设置了“buggy”背景,所以只需在设置背景后保存然后恢复填充值,例如:

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

    编辑: 作为替代方案,您不必使用之前的 padding 值,也可以使用尺寸值:

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

    【讨论】:

    • 这可以治愈它,谢谢。在我的例子中,drawable 是一个有九个补丁的 PNG。
    • 啊,确实如此。在 setBackgroundDrawable() 中查看 View 的代码 (j.mp/kxQJIJ)。它显然使用drawable的填充覆盖了填充。但是看看 Drawable 资源文档,除了形状之外没有任何东西支持填充,所以这可能就是它失败的原因。
    • 而且似乎 Romain Guy 只是将其关闭为“按预期工作”。代码中有一条注释证明了这种行为,所以它是故意的。我想如果它被记录在某个地方会更好。
    • 这绝对不是“按预期工作”,当我的意思是使用 setBackgroundResource() 仅更改图像的背景资源而不更改任何其他属性时,我从没想到它会影响填充的元素。
    • Romain 说“设置图像重置填充的原因是因为 9-patch 图像可以编码填充。如果缺失,我们假设填充为 0。”它应该是“如果缺少 && is9Patch()”恕我直言。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      除了 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);
      }
      

      【讨论】:

        【解决方案4】:

        在 Monodroid 中,如果我发布对 SetBackgroundResource 的调用,则顶部填充和底部填充保持不变

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

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

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

        【讨论】:

          【解决方案5】:

          这在 Lollipop 中是固定的,所以

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

          【讨论】:

          • 不,这在 Lollipop 中没有修复(至少在我的库存 5.1 Moto G ROM 上没有)
          • 自 KitKat 以来已修复此问题,因此检查应为 Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.KITKAT
          • 我的 Pixel 2 API 29 上仍然没有修复