Как ссылаться на атрибуты стиля из прорисовки?
Я хочу иметь 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>
Этот метод отлично работает, что позволяет мне легко создавать и изменять несколько тем. Проблема в том, что кажется, что его можно использовать только в представлениях, а не в Drawables.
Например, ссылка на значение из View внутри макета работает:
<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
, но то же самое происходит.
Как я мог это сделать? И почему это работает в представлениях, а не в Drawables? Я не могу найти это ограничение нигде в документации...
4 ответа
По моему опыту, невозможно ссылаться на атрибут в формате XML.
Для того, чтобы сделать вашу тему вам необходимо:
- Создайте один xml drawable для темы.
Включите нужный вам цвет, который можно нарисовать непосредственно с помощью
@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>
Добавьте свой drawable в ваш theme.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, это возможно для списков состояний цвета. Вы можете использовать метод AppCompatResources.getColorStateList(Context context, 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, чтобы она работала на более старых версиях (до Lollipop) Android.
К сожалению, подобный метод для drawables не работает с атрибутами стиля.
Я ответил на тот же вопрос в /questions/6346861/android-selector-drawable-ne-rabotaet-s-atributami/55335545#55335545, но я также опубликую его здесь:
Я столкнулся с той же проблемой, и по состоянию на 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>
вытяжка /colorPrimaryDarkDrawable
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
<solid android:color="?attr/colorPrimaryDark" />
</shape>
Надеюсь, это поможет!!
Как сказал @marmor, теперь это поддерживается в API 21. Но для тех из нас, кому необходимо поддерживать устаревшие версии Android, вы можете использовать эту функцию. Используя библиотеку поддержки v7, вы все равно можете использовать ее в приложениях с минимальным уровнем SDK вплоть до 7.
AppCompatImageView
В библиотеке поддержки Android v7 реализована бесплатная версия этой функции. Просто замените ваши обычаи ImageView
с AppCompatImageView
,