Как ссылаться на атрибуты стиля из чертежа?

Я хочу иметь две темы для моего приложения. Для этого я определил некоторые атрибуты, например:

 <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>

Этот метод отлично работает, что позволяет мне легко создавать и изменять несколько тем. Проблема в том, что кажется, что ее можно использовать только в представлениях, а не в 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? Я не могу найти это ограничение где-нибудь в документации...

Ответ 1

По моему опыту невозможно ссылаться на атрибут в xml drawable.
Чтобы сделать свою тему вам нужно:

  • Создайте один xml для каждой темы.
  • Включите необходимый цвет в выпрямляемый непосредственно с тегом @color или #RGB.

Создайте атрибут для вашего drawable в 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>

Добавьте свой drawable в ваш theme.xml.

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

Ссылайтесь на свои рисунки в своем макете, используя свой атрибут.

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

Ответ 2

Начиная с lollipop (API 21) эта функция поддерживается, см. https://code.google.com/p/android/issues/detail?id=26251

Однако, если вы настроите таргетинг на устройства без леденца, не используйте его, поскольку он будет аварийно, используйте обходной путь в принятом ответе.

Ответ 3

Невозможно ссылаться на атрибуты стиля из drawables на устройствах pre-Lollipop, но это возможно для списков состояния цвета. Вы можете использовать метод AppCompatResources.getColorStateList(контекстный контекст, int resId) из библиотеки поддержки Android. Недостатком является то, что вам придется программировать эти списки состояний цвета.

Вот очень простой пример.

цвет /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 Support Library, чтобы заставить его работать с более старыми версиями (pre-Lollipop) Android.

К сожалению, аналогичный метод для drawables не работает со атрибутами стиля.

Ответ 4

Как сказал @marmor, это теперь поддерживается API 21. Но для тех, кто нуждается в поддержке устаревших версий Android, вы можете использовать эту функцию. Используя библиотеку поддержки v7, вы все равно можете использовать ее в приложениях с минимальным уровнем SDK вплоть до 7.

В AppCompatImageView в библиотеке поддержки Android v7 реализована ошибка в этой функции. Просто замените ваши слова ImageView на AppCompatImageView.