如何从drawable引用样式属性?

MM.*_*MM. 87 android android-theme android-drawable android-attributes

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

 <attr format="color" name="item_background" />
Run Code Online (Sandbox Code Playgroud)

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

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

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>
Run Code Online (Sandbox Code Playgroud)

这种方法效果很好,允许我轻松地创建和修改几个主题.问题是它似乎只能在Views中使用,而不能在Drawables中使用.

例如,引用布局内View的值可以:

 <TextView android:background="?item_background" />
Run Code Online (Sandbox Code Playgroud)

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

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>
Run Code Online (Sandbox Code Playgroud)

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

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2
Run Code Online (Sandbox Code Playgroud)

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

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

L. *_* G. 152

根据我的经验,无法在xml drawable中引用属性.
为了使您的主题成为您需要:

  • 每个主题创建一个xml drawable.
  • 使用@color标签或#RGB格式直接绘制所需的颜色.

attrs.xml中为drawable 创建一个属性.

<?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>
Run Code Online (Sandbox Code Playgroud)

将drawable添加到theme.xml中.

<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
   <item name="my_drawable">@drawable/my_drawable</item>
</style>
Run Code Online (Sandbox Code Playgroud)

使用您的属性在布局中引用您的drawable.

<TextView android:background="?my_drawable" />
Run Code Online (Sandbox Code Playgroud)

  • 看来,如果你想要保持兼容性,这个解决方案仍然是必要的......是的,它是固定的,主题颜色被很好地引用,但相同的代码在不同的pre-L设备上运行,实际上attr引用不起作用pre-L设备!LoL ..所以对我来说,如果我不得不维持不同的抽签,这是不固定的. (18认同)
  • 哎呀!对于Google来说,这应该是最优先考虑的事情.如果你在应用程序中有多个主题,那么?attr-reference表示法是非常有用和重要的,它几乎不可能没有.现在我必须为每个自定义按钮类型制作三个可绘制的XML! (4认同)
  • 我希望我可以两次投票.只是尝试简化我的形状以使用引用而不是硬编码#RGB并得到相同的错误.来到SO寻求解决方案,并找到了我在2周前提出的相同答案!(捂脸) (2认同)
  • 这是超级忍者! (2认同)
  • 多数民众赞成我想要的 <21 SDK中非常简单和漂亮的解决方案. (2认同)
  • 谷歌WTF???为什么为什么为什么?... android 中的任何简单任务总是很困难吗?!跆拳道?! (2认同)

mar*_*mor 16

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

但是,如果您的目标是没有棒棒糖的设备,请不要使用它,因为它会崩溃,而是使用接受的答案中的变通方法.

  • 不,在棒棒糖中,它不是一个实现的功能,而是一个明显的错误修复.那是一个严重的错误. (3认同)
  • 不,支持库是一组可以在旧设备上使用的API,这种行为改变在编译器和构建工具中,因此它与支持库无关. (2认同)

rub*_*ubo 5

虽然不可能在Lollipop 之前的设备上从可绘制对象中引用样式属性,但颜色状态列表是可能的。您可以使用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>
Run Code Online (Sandbox Code Playgroud)

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

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />
Run Code Online (Sandbox Code Playgroud)

而最重要的是:

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

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

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


Pol*_*Pol 5

我在/sf/answers/4162708861/中回答了同样的问题,但我也会将其发布在这里:

我遇到了同样的问题,截至 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>
Run Code Online (Sandbox Code Playgroud)

您可以将 ?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>
Run Code Online (Sandbox Code Playgroud)

可绘制对象将定义为:

可绘制/颜色PrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>
Run Code Online (Sandbox Code Playgroud)

可绘制/颜色PrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!!