【问题标题】:Dynamically change drawable colors动态更改可绘制颜色
【发布时间】:2015-04-01 14:28:07
【问题描述】:

在我的应用程序中,我有很多用 xml 文件定义的可绘制对象。例如,我有一个这样定义的按钮:

button.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bottom 3dp Shadow -->
<item android:top="3dp">
    <shape android:shape="rectangle">
          <corners android:radius="3dp" />
          <solid android:color="@color/black_30" />   
    </shape>
</item>
<!-- green top color -->
<item android:top="3dp" android:bottom="3dp" android:id="@+id/background">
    <shape android:shape="rectangle">
        <corners android:radius="3dp" />
        <solid android:color="@color/green1" />           
    </shape>
 </item>
</layer-list>

然后我显示一个这样的按钮:

layout.xml
<Button
        android:id="@+id/button"
        android:layout_gravity="center"
        android:layout_height="60dp"
        android:layout_width="fill_parent"
        android:textSize="17sp"
        android:gravity="center"
        android:background="@drawable/button" />

当我在应用程序中导航时,我想“主题化”一些视图(一些颜色随着上下文的变化而变化),为此我希望能够动态更改按钮的颜色(绿色 1)在运行时。

1) 第一个不错的方法是使用?attr/my_color 更改button.xml 中的颜色定义。然后在主题文件style.xml中定义我需要的不同颜色值。然后在运行时,我可以切换到所需的主题,这将起作用。完整的步骤在这里:

How to reference colour attribute in drawable?

问题是它适用于 Android 5 但不适用于 Android 4(我需要支持此版本)(我们收到 android.view.InflateException: Binary XML file line #2: Error inflating class &lt;unknown&gt;

2)第二种方法是在代码中加载drawable,然后使用setColor改变drawable的颜色:(用Xamarin.Android写的,但我相信你会理解对应的Java版本)

LayerDrawable button = (LayerDrawable)Resources.GetDrawable(Resource.Drawable.normal_question_button);
GradientDrawable background = (GradientDrawable)button.FindDrawableByLayerId(Resource.Id.background);
background.SetColor(Android.Graphics.Color.Red.ToArgb());

好消息是它可以工作......但随机......有时当我再次显示按钮时,它仍然是显示的原始绿色。有时,它是新的颜色......一旦我有两种行为中的一种,相同的颜色可以停留很多时间,然后突然又变成正确的颜色。

有人可以解释一下吗?是否有一些关于可绘制对象的缓存会产生这种问题?

3) 我在考虑第三种解决方案:动态更改colors.xml(其中定义了green1)中定义的颜色,但这似乎不可能

【问题讨论】:

  • 您好,在我的导航抽屉图标(可在 imageViews 中绘制)中,我使用 setColorFilter 方法。例如,如果我有一个 100% 不透明度的黑色图标,使用这种方法我可以得到一个 100% 不透明度的具有某种颜色的图标。将它与 setImageAlpha 或 setAlpha 相结合,我可以获得所有不透明度中所有颜色的所有图标。如果这对您有用,请告诉我添加到答案中。
  • 您是否尝试在外部 LayerDrawable 上调用 invalidateSelf()?
  • @pskink:我尝试在两个可绘制对象上调用 invalidateSelf() 并且没有任何变化
  • @Dahnark:如果我使用 setColorFilter 而不是 setColor,我的按钮将不再有颜色。 background.SetColorFilter(new PorterDuffColorFilter(Android.Graphics.Color.Red, PorterDuff.Mode.Multiply));
  • 不不,setColorFilter 对第一种颜色起作用。我的图标是黑色的(它们是 .png),然后 setColorFilter 将这个纯黑色更改为其他纯色。

标签: java c# android xamarin.android android-drawable


【解决方案1】:

事实上对于 2) 一个非常简单的解决方案是:

而不是尝试自定义来自 xml 文件的可绘制对象:

 LayerDrawable button = (LayerDrawable)Resources.GetDrawable(Resource.Drawable.normal_question_button);
GradientDrawable background = (GradientDrawable)button.FindDrawableByLayerId(Resource.Id.background);
background.SetColor(Android.Graphics.Color.Red.ToArgb());

一旦我们有了它们的实例,我们就可以直接改变每个按钮的颜色:

LayerDrawable buttonDrawable = _button.Background;
GradientDrawable background = (GradientDrawable)buttonDrawable.FindDrawableByLayerId(Resource.Id.background);
background.SetColor(Android.Graphics.Color.Red.ToArgb());

【讨论】: