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


Я хочу иметь 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>

этот метод отлично работает, что позволяет мне легко создавать и изменять несколько тем. Проблема в том, что кажется, что его можно использовать только в представлениях, а не в чертежах.

например, ссылка на значение из вида внутри макета работает:

 <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, но то же самое происходит.

как я мог это сделать? И почему он работает в представлениях, но не в чертежах? Я не могу найти это ограничение нигде в в документация...

4 82

4 ответа:

по моему опыту невозможно ссылаться на атрибут в XML drawable.
Для того, чтобы сделать вашу тему вам нужно:

  • создать один xml drawable для каждой темы.
  • включите необходимый цвет в вас drawable сразу с @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 к вашему тема.xml.

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

ссылка на ваш drawable в вашем макете с помощью атрибута.

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

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

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

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

вот очень простой образец.

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

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

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

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