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

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

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


person MM.    schedule 07.11.2011    source источник
comment
Это может быть дубликатом следующего вопроса: stackoverflow.com/questions/7529574/   -  person Paul Lammertsma    schedule 09.11.2011
comment
@ Мартин М., что ты понял с этим?   -  person user123321    schedule 28.12.2011
comment
Любое решение для этого еще? Я натыкаюсь на ту же стену   -  person Guillaume    schedule 12.01.2012
comment
Еще один более свежий вопрос здесь: stackoverflow.com/q/12115125/317889 Та же проблема. Разберись с этим Гугл.   -  person HGPB    schedule 25.08.2012
comment
По-видимому, эта проблема была решена в предварительной версии Android L, как указано здесь: код. google.com/p/android/issues/detail?id=26251   -  person Bianca Daniciuc    schedule 10.07.2014
comment
Вау! Лучше поздно, чем никогда, я думаю :)   -  person MM.    schedule 10.07.2014
comment
Благодаря этому вопросу... Приятно знать, что он исправлен, но наш код работает на разных устройствах pre-L. Таким образом, мы все равно должны поддерживать разные чертежи. Кто-нибудь может подтвердить?   -  person Davideas    schedule 17.05.2015


Ответы (5)


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

  • Создайте один XML-файл для каждой темы.
  • Включите нужный цвет в свой рисунок непосредственно с помощью тега @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>

Добавьте свой рисунок в свой theme.xml.

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

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

<TextView android:background="?my_drawable" />
person L. G.    schedule 20.11.2012
comment
Кажется, что это решение по-прежнему необходимо, если вы хотите сохранить совместимость... Да, из L оно исправлено, и цвет темы хорошо указан, но один и тот же код работает на разных устройствах до L, и на самом деле ссылка attr не работает на устройства до L! LoL .. Так что для меня это не исправлено, если мне все равно придется поддерживать разные рисунки. - person Davideas; 17.05.2015
comment
Хотел бы я дважды проголосовать за это. Просто попытался упростить мои фигуры, чтобы использовать ссылки вместо жестко запрограммированного #RGB, и получил ту же ошибку. Пришел на SO за решением и нашел тот же ответ, за который я проголосовал 2 недели назад! (фейспалм) - person Tiksi; 09.09.2015
comment
Спасибо тебе, друг. Ты рок-звезда!! - person Umair; 07.01.2016
comment
Это супер ниндзя! - person MariusBudin; 20.01.2016
comment
прежде чем публиковать новый вопрос, который я хочу задать здесь, у меня есть тип = 0x2 на этом ‹ProgressBar android:id=@+id/progressbar android:progressDrawable=@drawable/progress_single_input_form android:layout_width=match_parent android:layout_gravity=bottom/ › Что мне не хватает? (эта часть большего xml, и когда я ее удаляю, все остальное работает), это происходит только на andorid 4.2.2 - person Camilo Casadiego; 12.02.2016
comment
Трудно ответить с таким небольшим количеством информации, я рекомендую вам опубликовать вопрос с подробным описанием проблемы. - person L. G.; 12.02.2016
comment
АРХ! Это должно быть высшим приоритетом для Google, чтобы исправить бэкпорт! Обозначение ?attr-reference настолько полезно и важно, что без него почти невозможно жить, если у вас есть несколько тем в приложении. Прямо сейчас мне нужно сделать три рисуемых XML-файла для каждого из пользовательских типов кнопок! - person Stephan Henningsen; 27.10.2016
comment
Привет. Можно ссылаться на пользовательский атрибут из drawable, но в API 21 и выше. Вставьте пример. - person Santiago SR; 27.12.2016
comment
Это я хочу. очень простое и приятное решение в ‹ 21 SDK. - person Adnan Abdollah Zaki; 03.01.2017
comment
Это просто, но для новой темы нужно добавить новые файлы для всех элементов пользовательского интерфейса, это долгая задача. - person Shamsul Arefin Sajib; 22.04.2018
comment
Гугл ВТФ??? Почему, почему, почему?... любая простая задача в андроиде всегда очень сложна?! ВТФ?! - person maXp; 14.06.2018
comment
Но есть еще одна ошибка, когда я ее реализовал Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040134 a=-1} - person HendraWD; 18.06.2018

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

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

person marmor    schedule 20.05.2015
comment
Есть ли шанс использовать какую-то библиотеку поддержки, чтобы заставить ее работать с API до L? - person Ivan; 30.10.2015
comment
Нет, библиотека поддержки — это набор API-интерфейсов, которые можно использовать на старых устройствах. Это изменение поведения связано с компилятором и инструментами сборки, поэтому оно не связано с библиотекой поддержки. - person marmor; 01.11.2015
comment
Нет, в леденце это была не реализованная функция, а вопиющее исправление ошибки. И серьезная ошибка в этом. - person Adrian Sicaru; 10.12.2015
comment
блин, я думал, что у меня есть хорошее решение темы. теперь мне нужно вернуться и создать кучу рисунков селектора кнопок. - person filthy_wizard; 18.02.2016

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

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

person rubo    schedule 10.12.2016

Я ответил на тот же вопрос в 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>

Drawables будут определены как:

drawable/colorPrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>

drawable/colorPrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>

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

person Pol    schedule 24.12.2019

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

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

person Jade    schedule 11.05.2016
comment
Звучит обнадеживающе! Но проблема в форме Drawable, а не в представлении. У меня есть представление appcompat, ссылающееся (в качестве фона) на фигуру, которая использует attr для получения тематического цвета, и оно падает с вышеуказанной ошибкой на ‹21. Есть ли appcompat drawable, который я пропустил? - person NeilS; 19.08.2016
comment
Android 5.0.1 jy Хуавей все-таки затронул. - person southerton; 11.11.2019