102

我想为我的应用程序提供 2 个可选主题。为此,我定义了一些属性,如下所示:

 <attr format="color" name="item_background" />

然后,我创建了两个主题,如下所示:

  <style name="ThemeA">
     <item name="item_background">#123456</item>
 </style>

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>

这种方法效果很好,让我可以轻松创建和修改多个主题。问题是它似乎只能在 Views 中使用,而不能在 Drawables 中使用

例如,从布局内的视图中引用一个值是可行的:

 <TextView android:background="?item_background" />

但是在 Drawable 中做同样的事情不会:

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>

运行应用程序时出现此错误:

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2

如果不是?item_background我使用硬编码的颜色,它可以工作,但这不允许我使用我的主题。我也试过?attr:item_background了,但同样的事情发生了。

我怎么能这样做?为什么它在 Views 中有效,但在 Drawables 中无效?我在文档中的任何地方都找不到这个限制......

4

5 回答 5

177

以我的经验,不可能在 XML 可绘制对象中引用属性。
为了制作您的主题,您需要:

  • 每个主题创建一个 XML 可绘制对象。
  • @color使用标签或#RGB 格式将所需的颜色直接包含在可绘制对象中。

在attrs.xml中为您的可绘制对象创建一个属性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <!-- Attributes must be lowercase as we want to use them for drawables -->
   <attr name="my_drawable" format="reference" />
</resources>

将您的可绘制对象添加到您的theme.xml中。

<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
   <item name="my_drawable">@drawable/my_drawable</item>
</style>

使用您的属性在布局中引用您的可绘制对象。

<TextView android:background="?my_drawable" />
于 2012-11-20T10:55:18.877 回答
20

lollipop(API 21)开始支持此功能,请参阅 https://code.google.com/p/android/issues/detail?id=26251

但是,如果您的目标设备没有棒棒糖,请不要使用它,因为它会崩溃,请改用已接受答案中的解决方法。

于 2015-05-20T13:47:55.823 回答
5

虽然不可能从棒棒糖之前的设备上的可绘制对象中引用样式属性,但对于颜色状态列表是可能的。您可以使用Android 支持库中的AppCompatResources.getColorStateList(Context context, int resId)方法。缺点是您必须以编程方式设置这些颜色状态列表。

这是一个非常基本的例子。

颜色/my_color_state.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_checked="true" android:color="?colorControlActivated" />
  <item android:color="?colorControlNormal" />
</selector>

需要颜色状态列表的小部件:

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />

还有最重要的:

ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);    
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);

好吧,这不是最优雅或最短的方法,但这是 Android 支持库所做的,以使其在 Android 的旧版本(棒棒糖之前)上工作。

不幸的是,drawables 的类似方法不适用于样式属性。

于 2016-12-10T23:59:51.697 回答
5

我在https://stackoverflow.com/a/59467269/3841352中回答了同样的问题,但我也会在这里发布:

我遇到了同样的问题,截至 2019 年尚未解决,因此您不能将选择器中引用的属性作为可绘制对象。我将分享我为这个问题得到的解决方案,因为我没有看到它在这里发布。我在错误报告的最后一条评论中找到了它。

解决方法基本上是创建一个可绘制资源,该资源将引用属性值。

为了说明您的情况,解决方案将代替:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="?attr/colorPrimary"/>
</selector>

您将替换 ?attr/* 为可绘制资源:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="@drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="@drawable/colorPrimaryDrawable"/>
</selector>

可绘制对象将定义为:

drawable/colorPrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>

drawable/colorPrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>

希望能帮助到你!!

于 2019-12-24T10:23:30.743 回答
0

正如@marmor 所说,API 21 现在支持此功能。但是对于我们需要支持旧版 Android 的用户,您可以使用此功能。使用 v7 支持库,您仍然可以在最低 SDK 级别一直到 7 的应用程序上使用它。

v7 Android 支持库AppCompatImageView中有一个无错误的实现此功能。只需将您的用法替换ImageViewAppCompatImageView

于 2016-05-11T03:51:21.757 回答