Jak odwołać się do atrybutów stylu z rysunków?

98

Chcę mieć 2 motywy do wyboru dla mojej aplikacji. W tym celu zdefiniowałem kilka atrybutów, na przykład:

 <attr format="color" name="item_background" />

Następnie stworzyłem oba motywy, takie jak ten:

  <style name="ThemeA">
     <item name="item_background">#123456</item>
 </style>

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>

Ta metoda działa świetnie, pozwalając mi łatwo tworzyć i modyfikować kilka motywów. Problem polega na tym, że wydaje się, że można go używać tylko w widokach, a nie w Drawables .

Na przykład odwołanie do wartości z widoku wewnątrz układu działa:

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

Ale zrobienie tego samego w Drawable nie:

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>

Otrzymuję ten błąd podczas uruchamiania aplikacji:

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2

Jeśli zamiast tego ?item_backgroundużywam zakodowanego na stałe koloru, działa, ale to nie pozwala mi na używanie moich motywów. Też próbowałem ?attr:item_background, ale to samo się dzieje.

Jak mogłem to zrobić? I dlaczego działa w widokach, ale nie w Drawables? Nie mogę znaleźć tego ograniczenia w dokumentacji ...

MM.
źródło
To może być duplikat następującego pytania: stackoverflow.com/questions/7529574/…
Paul Lammertsma
@Martin M., co z tym wymyśliłeś?
user123321
Jakieś rozwiązanie tego problemu? Uderzam dokładnie w tę samą ścianę
Guillaume
Kolejne nowsze pytanie: stackoverflow.com/q/12115125/317889 Ten sam problem. Sortuj to, Google.
HGPB
3
Najwyraźniej ten problem został rozwiązany w podglądzie Androida L, jak określono tutaj: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Odpowiedzi:

165

Z mojego doświadczenia wynika, że ​​nie jest możliwe odwołanie się do atrybutu w pliku XML do rysowania.
Aby utworzyć motyw, musisz:

  • Utwórz jeden plik XML do rysowania na temat.
  • Dołącz wymagany kolor do rysowania bezpośrednio za pomocą @colortagu lub formatu #RGB.

Utwórz atrybut do rysowania w 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>

Dodaj swój drawable do pliku theme.xml .

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

Odwołaj się do elementu do rysowania w układzie, używając atrybutu.

<TextView android:background="?my_drawable" />
LG
źródło
20
Wygląda na to, że to rozwiązanie jest nadal konieczne, jeśli chcesz zachować kompatybilność ... Tak od L jest to naprawione i kolor motywu jest dobrze powiązany, ale ten sam kod działa na różnych urządzeniach pre-L i faktycznie odniesienie attr nie działa urządzenia pre-L! LoL .. Więc dla mnie nie jest ustalone, czy i tak muszę utrzymywać różne elementy do rysowania.
Davideas
2
Chciałbym móc dwukrotnie głosować za tym. Po prostu próbowałem usprawnić moje kształty, aby używały odwołań zamiast zakodowanego na stałe #RGB i otrzymałem ten sam błąd. Przyszedłem do SO po rozwiązanie i znalazłem tę samą odpowiedź, na którą głosowałem 2 tygodnie temu! (facepalm)
Tiksi
2
To jest super ninja!
MariusBudin
4
ARGH! Powinno to być priorytetem dla Google, aby naprawić backport! Notacja atr-reference jest tak niezwykle przydatna i ważna, że ​​życie bez niej jest prawie niemożliwe, jeśli masz wiele motywów w aplikacji. W tej chwili muszę stworzyć trzy możliwe do rysowania pliki XML dla każdego z niestandardowych typów przycisków!
Stephan Henningsen
2
Tego chcę. bardzo proste i przyjemne rozwiązanie w <21 SDK.
Adnan Abdollah Zaki,
20

Począwszy od lollipop(API 21) ta funkcja jest obsługiwana, zobacz https://code.google.com/p/android/issues/detail?id=26251

Jeśli jednak celujesz w urządzenia bez Lollipopa, nie używaj go, ponieważ ulegnie awarii, zamiast tego użyj obejścia w zaakceptowanej odpowiedzi.

marmor
źródło
Czy jest jakaś szansa na użycie biblioteki pomocniczej, aby działała na interfejsach API wcześniejszych niż L?
Ivan
2
Nie, biblioteka obsługi to zestaw interfejsów API, które mogą być używane na starszych urządzeniach, ta zmiana zachowania dotyczy kompilatora i narzędzi do kompilacji, więc nie jest związana z biblioteką obsługi.
marmor
3
Nie, w Lollipopie nie była to zaimplementowana funkcja, ale rażąca poprawka błędu. I to poważny błąd.
Adrian Sicaru
cholera, myślałem, że mam fajne rozwiązanie tematyczne. teraz muszę cofnąć się i stworzyć kilka elementów do wyboru z selektorem przycisków.
filthy_wizard
4

Chociaż nie jest możliwe odwoływanie się do atrybutów stylu z elementów do rysowania na urządzeniach sprzed wersji Lollipop , ale jest to możliwe w przypadku list stanów kolorów. Możesz użyć metody AppCompatResources.getColorStateList (kontekst kontekstu, int resId) z biblioteki obsługi systemu Android. Wadą jest to, że będziesz musiał programowo ustawić te listy stanu kolorów.

Oto bardzo podstawowy przykład.

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>

Widżet, który potrzebuje listy stanów kolorów:

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />

I co najważniejsze:

ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);    
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);

Cóż, nie jest to najbardziej elegancki ani najkrótszy sposób, ale właśnie to robi biblioteka obsługi Androida, aby działała na starszych wersjach (przed Lollipopem) Androida.

Niestety, podobna metoda dla drawables nie działa z atrybutami stylu.

rubo
źródło
2

Odpowiedziałem na to samo pytanie w https://stackoverflow.com/a/59467269/3841352, ale zamieści je również tutaj:

Napotkałem ten sam problem i od 2019 r. Nie został on rozwiązany, więc nie można odwoływać się do atrybutu w selektorze jako do narysowania. Podzielę się rozwiązaniem, które otrzymałem, ponieważ nie widzę go tutaj opublikowanego. Znalazłem to w ostatnim komentarzu do zgłoszenia błędu .

Sposób obejścia problemu polega w zasadzie na utworzeniu zasobu do rysowania, który będzie odwoływał się do wartości atrybutu.

Aby zilustrować Twój przypadek, rozwiązaniem byłoby zamiast:

<?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>

zamieniłbyś? attr / * na zasób do rysowania:

<?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 zostałyby zdefiniowane jako:

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>

Mam nadzieję, że to pomoże!!

Pol
źródło
0

Jak stwierdził @marmor, jest to teraz obsługiwane w API 21. Ale dla tych, którzy potrzebują obsługi starszych wersji Androida, możesz użyć tej funkcji. Korzystając z biblioteki obsługi wersji 7, możesz nadal używać jej w aplikacjach z minimalnym poziomem SDK aż do 7.

AppCompatImageViewW v7 Biblioteka Pomoc Android ma wolny od błędów realizację tej funkcji. Wystarczy wymienić swoje zwyczaje ImageViewz AppCompatImageView.

Benzoes
źródło
2
Brzmi obiecująco! Ale problem tkwi w kształcie do rysowania, a nie w widoku. Mam widok Appcompat odwołujący się (jako tło) do kształtu, który używa atr, aby uzyskać kolor tematyczny i przewraca się z powyższym błędem na <21. Czy jest jakaś aplikacja, którą przegapiłem?
NeilS,
Android 5.0.1 jy nadal dotyczy Huawei.
Southerton