Wie verweise ich auf Stilattribute aus einem Drawable?


96

Ich möchte 2 auswählbare Themen für meine Anwendung haben. Zu diesem Zweck habe ich einige Attribute wie folgt definiert:

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

Dann habe ich beide Themen wie folgt erstellt:

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

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

Diese Methode funktioniert hervorragend und ermöglicht mir das einfache Erstellen und Ändern mehrerer Themen. Das Problem ist, dass es anscheinend nur in Ansichten und nicht in Drawables verwendet werden kann .

Das Verweisen auf einen Wert aus einer Ansicht in einem Layout funktioniert beispielsweise wie folgt:

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

Aber dasselbe in einem Drawable zu tun, bedeutet nicht:

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

Ich erhalte diesen Fehler beim Ausführen der Anwendung:

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

Wenn ?item_backgroundich keine fest codierte Farbe verwende, funktioniert dies, aber ich kann meine Themen nicht verwenden. Ich habe es auch versucht ?attr:item_background, aber das gleiche passiert.

Wie könnte ich das machen? Und warum funktioniert es in Ansichten, aber nicht in Drawables? Ich kann diese Einschränkung nirgendwo in der Dokumentation finden ...


Dies könnte ein Duplikat der folgenden Frage sein: stackoverflow.com/questions/7529574/…
Paul Lammertsma

@ Martin M., was hast du damit herausgefunden?
user123321

Irgendeine Lösung dafür schon? Ich
Guillaume

Eine weitere neuere Frage hier: stackoverflow.com/q/12115125/317889 Gleiches Problem. Sortieren Sie es aus Google.
HGPB

3
Anscheinend wurde dieses Problem in der Android L-Vorschau behoben, wie hier angegeben: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Antworten:


161

Nach meiner Erfahrung ist es nicht möglich, ein Attribut in einer XML-Zeichnung zu referenzieren.
Um Ihr Thema zu erstellen, müssen Sie:

  • Erstellen Sie eine XML-Zeichnung pro Thema.
  • Fügen Sie die gewünschte Farbe direkt mit dem @colorTag- oder # RGB-Format in Ihre Zeichnung ein.

Erstellen Sie in attrs.xml ein Attribut für Ihre Zeichnung .

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

Fügen Sie Ihr Zeichen zu Ihrer theme.xml hinzu .

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

Verweisen Sie mit Ihrem Attribut auf Ihre Zeichnung in Ihrem Layout.

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

20
Es scheint, dass diese Lösung immer noch notwendig ist, wenn Sie die Kompatibilität beibehalten möchten ... Ja, ab L ist sie behoben und die Themenfarbe ist gut referenziert, aber der gleiche Code wird auf verschiedenen Geräten vor L ausgeführt, und tatsächlich funktioniert die attr-Referenz nicht Pre-L-Geräte! LoL .. Für mich ist es also nicht festgelegt, ob ich sowieso verschiedene Drawables pflegen muss.
Davideas

2
Ich wünschte, ich könnte dies zweimal positiv bewerten. Ich habe gerade versucht, meine Formen zu optimieren, um Referenzen anstelle von fest codiertem #RGB zu verwenden, und habe den gleichen Fehler erhalten. Kam zu SO für eine Lösung und fand die gleiche Antwort, die ich vor 2 Wochen upvoted habe! (Gesichtspalme)
Tiksi

2
Das ist super Ninja!
Marius Budin

4
ARGH! Dies sollte für Google oberste Priorität haben, um eine Backport-Korrektur für! Die? Attr-Referenznotation ist so äußerst nützlich und wichtig, dass es so gut wie unmöglich ist, ohne sie zu leben, wenn Sie mehrere Themen in einer App haben. Im Moment muss ich drei zeichnbare XMLs für jeden der benutzerdefinierten Schaltflächentypen erstellen!
Stephan Henningsen

2
Das will ich. sehr einfache und schöne Lösung in <21 SDK.
Adnan Abdollah Zaki

20

Ab lollipop(API 21) wird diese Funktion unterstützt, siehe https://code.google.com/p/android/issues/detail?id=26251

Wenn Sie jedoch auf Geräte ohne Lutscher abzielen, verwenden Sie diese nicht, da sie abstürzen können. Verwenden Sie stattdessen die Problemumgehung in der akzeptierten Antwort.


Gibt es eine Möglichkeit, eine Art Support-Bibliothek zu verwenden, damit sie auf Pre-L-APIs funktioniert?
Ivan

2
Nein, die Support-Bibliothek besteht aus einer Reihe von APIs, die auf älteren Geräten verwendet werden können. Diese Verhaltensänderung befindet sich im Compiler und in den Build-Tools und ist daher nicht mit der Support-Bibliothek verbunden.
Marmor

3
Nein, in Lollipop war es keine implementierte Funktion, sondern eine krasse Fehlerbehebung. Und ein schwerwiegender Fehler.
Adrian Sicaru

Verdammt, ich dachte, ich hätte eine schöne Themenlösung. Jetzt muss ich zurückgehen und eine Reihe von Schaltflächen zur Auswahl von Schaltflächen erstellen.
filthy_wizard

4

Es ist zwar nicht möglich, Stilattribute aus Drawables auf Pre-Lollipop- Geräten zu referenzieren , aber es ist für Farbstatuslisten möglich. Sie können die AppCompatResources.getColorStateList-Methode (Context context, int resId) aus der Android Support Library verwenden. Der Nachteil ist, dass Sie diese Farbstatuslisten programmgesteuert festlegen müssen.

Hier ist ein sehr einfaches Beispiel.

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>

Ein Widget, das eine Farbstatusliste benötigt:

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

Und das Wichtigste:

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

Nun, nicht der eleganteste oder kürzeste Weg, aber genau das tut die Android Support Library, damit sie auf älteren Versionen (vor Lollipop) von Android funktioniert.

Leider funktioniert die ähnliche Methode für Drawables nicht mit Stilattributen.


1

Ich habe die gleiche Frage unter https://stackoverflow.com/a/59467269/3841352 beantwortet, aber ich werde sie auch hier posten:

Ich bin auf dasselbe Problem gestoßen und seit 2019 ist es nicht behoben, sodass Sie kein Attribut in einem Selektor als Zeichenelement referenzieren können. Ich werde die Lösung, die ich für das Problem erhalten habe, teilen, da ich sie hier nicht sehe. Ich habe es im letzten Kommentar des Fehlerberichts gefunden .

Die Problemumgehung besteht im Wesentlichen darin, eine zeichnbare Ressource zu erstellen, die auf den Attributwert verweist.

Um Ihren Fall zu veranschaulichen, wäre die Lösung anstelle von:

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

Sie würden das? attr / * für eine zeichnbare Ressource ersetzen:

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

Die Drawables würden definiert als:

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>

Ich hoffe es hilft!!


0

Wie @marmor sagte, wird dies jetzt von API 21 unterstützt. Für diejenigen, die ältere Versionen von Android unterstützen müssen, können Sie diese Funktion verwenden. Mit der v7-Unterstützungsbibliothek können Sie sie weiterhin für Apps mit einem Mindest-SDK-Level bis zu 7 verwenden.

Die AppCompatImageViewin der v7 Android Support Library hat eine fehlerfreie Implementierung dieser Funktion. Ersetzen Sie einfach Ihre Verwendung von ImageViewdurch AppCompatImageView.


2
Klingt hoffnungsvoll! Das Problem liegt jedoch in der Zeichenform nicht in einer Ansicht. Ich habe eine Appcompat-Ansicht, die (als Hintergrund) auf eine Form verweist, die attr verwendet, um eine Themenfarbe zu erhalten, und die mit dem obigen Fehler auf <21 umkippt. Gibt es ein Appcompat Drawable, das ich verpasst habe?
NeilS

Android 5.0.1 jy Huawei noch betroffen.
Southton
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.