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

98

Я хочу иметь 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, но бывает то же самое.

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

ММ.
источник
Это может быть дубликатом следующего вопроса: stackoverflow.com/questions/7529574/…
Пол Ламмерцма,
@ Мартин М., что ты с этим понял?
user123321
Есть ли решение для этого? Я врезаюсь в ту же стену
Гийом
Еще один более свежий вопрос здесь: stackoverflow.com/q/12115125/317889 Та же проблема. Разберитесь в гугле.
HGPB
3
По-видимому, эта проблема была решена в предварительной версии Android L, как указано здесь: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Ответы:

166

По моему опыту, невозможно ссылаться на атрибут в XML-файле.
Для создания своей темы вам необходимо:

  • Создайте один 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>

Добавьте свой чертеж в свой theme.xml .

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

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

<TextView android:background="?my_drawable" />
LG
источник
20
Кажется, что это решение все еще необходимо, если вы хотите сохранить совместимость ... Да, от L оно исправлено, и цвет темы хорошо указан, но тот же код работает на разных устройствах pre-L, и на самом деле ссылка attr не работает на устройства pre-L! LoL .. Так что для меня это не исправлено, если мне все равно придется поддерживать разные чертежи.
Davideas
2
Хотел бы я проголосовать за это дважды. Просто попытался оптимизировать мои формы, чтобы использовать ссылки вместо жестко заданного #RGB, и получил ту же ошибку. Пришел в SO за решением и нашел тот же ответ, за который я проголосовал 2 недели назад! (facepalm)
Тикси
2
Это супер ниндзя!
MariusBudin
4
АРГХ! Это должно быть главным приоритетом для Google, чтобы исправить backport-fix! Обозначение? Attr-reference настолько полезно и важно, что без него почти невозможно жить, если у вас есть несколько тем в приложении. Прямо сейчас мне нужно сделать три доступных для рисования XML для каждого типа пользовательских кнопок!
Стефан Хеннингсен
2
Я хочу. очень простое и красивое решение в <21 SDK.
Аднан Абдолла Заки
20

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

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

мрамор
источник
Есть ли шанс использовать какую-то вспомогательную библиотеку, чтобы заставить ее работать на предварительных L API?
Иван
2
Нет, библиотека поддержки - это набор API-интерфейсов, которые можно использовать на старых устройствах, это изменение поведения есть в инструментах компилятора и сборки, поэтому оно не связано с библиотекой поддержки.
Marmor
3
Нет, в Lollipop это была не реализованная функция, а явное исправление ошибки. И при этом серьезная ошибка.
Адриан Сикару
блин, я думал, что у меня есть хорошее решение для тематики. теперь мне нужно вернуться и создать кучу элементов выбора кнопок.
filthy_wizard
4

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

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

рубо
источник
3

Я ответил на тот же вопрос в https://stackoverflow.com/a/59467269/3841352, но я также опубликую его здесь:

Я столкнулся с той же проблемой, и по состоянию на 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>

Чертежи будут определены как:

вытяжка / 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>

Надеюсь, это поможет!!

Pol
источник
0

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

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

Бенджамин
источник
2
Звучит обнадеживающе! Но проблема в фигуре Drawable, а не в представлении. У меня есть представление appcompat, ссылающееся (в качестве фона) на фигуру, которая использует attr для получения тематического цвета, и она падает с указанной выше ошибкой на <21. Есть ли приложение для рисования, которое я пропустил?
NeilS
Android 5.0.1 jy Huawei по-прежнему страдает.
southerton