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_background
uż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 ...
Odpowiedzi:
Z mojego doświadczenia wynika, że nie jest możliwe odwołanie się do atrybutu w pliku XML do rysowania.
Aby utworzyć motyw, musisz:
Dołącz wymagany kolor do rysowania bezpośrednio za pomocą
@color
tagu 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" />
źródło
Począwszy od
lollipop
(API 21) ta funkcja jest obsługiwana, zobacz https://code.google.com/p/android/issues/detail?id=26251Jeśli jednak celujesz w urządzenia bez Lollipopa, nie używaj go, ponieważ ulegnie awarii, zamiast tego użyj obejścia w zaakceptowanej odpowiedzi.
źródło
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:
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.
źródło
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!!
źródło
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.
AppCompatImageView
W v7 Biblioteka Pomoc Android ma wolny od błędów realizację tej funkcji. Wystarczy wymienić swoje zwyczajeImageView
zAppCompatImageView
.źródło