Как ссылаться на атрибуты стиля с помощью чертежа?

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

<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 я использую ?item_background , он работает, но это не позволяет мне использовать мои темы. Я также пробовал ?attr:item_background , но то же самое происходит.

Как я могу это сделать? И почему он работает в Views, но не в Drawables? Я не могу найти это ограничение где-нибудь в документации …

По моему опыту нельзя ссылаться на атрибут в 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" /> 

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

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

Хотя нельзя ссылаться на атрибуты стиля из чертежей на устройствах 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 не работает с атрибутами стиля.

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

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