Gleichnamige Attribute in attrs.xml für die benutzerdefinierte Ansicht

179

Ich schreibe einige benutzerdefinierte Ansichten, die einige gleichnamige Attribute aufweisen. In ihrem jeweiligen <declare-styleable>Abschnitt in attrs.xmlmöchte ich die gleichen Namen für Attribute verwenden:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView1">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>
</resources>

Ich erhalte eine Fehlermeldung myattr1und bin myattr2bereits definiert. Ich habe festgestellt, dass ich das formatAttribut für myattr1und myattr2in weglassen sollte MyView2, aber wenn ich das tue, erhalte ich den folgenden Fehler in der Konsole:

[2010-12-13 23:53:11 - MyProject] ERROR: In <declare-styleable> MyView2, unable to find attribute 

Gibt es eine Möglichkeit, dies zu erreichen, vielleicht eine Art Namensraum (nur Vermutung)?

Venator85
quelle

Antworten:

399

Lösung: Extrahieren Sie einfach gemeinsame Attribute aus beiden Ansichten und fügen Sie sie direkt als untergeordnete Elemente des <resources>Knotens hinzu:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myattr1" format="string" />
    <attr name="myattr2" format="dimension" />

    <declare-styleable name="MyView1">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>
</resources>
Venator85
quelle
11
Was passiert, wenn myattr1String in MyView1und Integer in ist MyView2?
Foxx1337
4
Ich denke nicht, z. B. können wir das Attribut 'Orientierung' haben und für einige Ansichten ist es 'horizontal' / 'vertikal' und für andere 'Landschaft' / 'Hochformat' / 'Quadrat'. Aus meiner Sicht handelt es sich um einen Fehler (oder zumindest ein inkonsistentes Verhalten) in Android (beachten Sie Folgendes: 1. Stilfähige Attribute beginnen immer mit Präfix = Ansichtsname und 2. Wenn Sie separate Bibliotheksprojekte für solche Ansichten erstellen, funktioniert alles einwandfrei )
se.solovyev
4
Wenn ich dieser Antwort folge, bekomme ich ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr für alle Ansichten, für die ich mich zu erklären versuche. Irgendwelche Ideen?
Dapp
45
@ Google: Crappy Design
Glenn Bech
6
@ foxx1337 Einfach benutzen <attr name="myattr1" format="string|integer" />. Funktioniert bei mir.
Mygod
57

Ich poste diese Antwort, da die oben veröffentlichte Lösung in Android Studio für mich nicht funktioniert hat. Ich muss meine benutzerdefinierten Attribute für meine benutzerdefinierten Ansichten freigeben, damit ich die oben genannte Lösung in Android Studio ausprobiert habe, aber kein Glück hatte. Also experimentiere ich und gehe einen Weg, es zu tun. Hoffe, es könnte jemandem helfen, der nach dem gleichen Problem sucht.

  <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <!-- parent styleable -->
     <declare-styleable name="MyView">
         <attr name="myattr1" format="string" />
         <attr name="myattr2" format="dimension" />
     </declare-styleable>

     <!-- inheriting parent styleable -->
     <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
    <declare-styleable name="MyView1" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myBackgroundColor" format="color"/>
    </declare-styleable>


    <!-- inheriting parent styleable -->
    <!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
    <declare-styleable name="MyView2" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myfont" format="string"/>
        ...
    </declare-styleable>
</resources>

Das funktioniert bei mir komplett. Wir müssen einen Elternteil stilisierbar machen und dann diesen Elternteil stilisierbar erben. Zum Beispiel, wie ich oben getan habe: Übergeordneter stilbarer Name MyView und erbte diesen an meinen anderen stilbaren Namen wie MyView1 bzw. MyView2.

Priya Singhal
quelle
1
Das hat bei mir funktioniert. Ich konnte keine Möglichkeit finden, die extrahierten Attribute im Code aus der akzeptierten Antwort zu referenzieren.
Nemanja Kovacevic
Hmm ... das ist komisch ... die akzeptierte Lösung scheint für mich gut zu funktionieren (targetSdkVersion 27). Vielleicht, weil Attribute wie "Text" häufig vorkommen und in einigen anderen attrs.xml vorhanden waren.
Aba
Ich habe es mit einem Namen versucht, der höchstwahrscheinlich ungewöhnlich ist und die akzeptierte Lösung hat immer noch für mich funktioniert.
Aba
Ich stimme dem ersten Kommentar zu! Es gibt keine Möglichkeit, auf einen extrahierten attr aus typedArray zu verweisen. Daher müssen Sie einen stilbaren Elternteil definieren
reavcn
Damit dies funktioniert , vergessen Sie nicht , dieses Attribut in Eltern anzusprechen und in Kind nicht (für Klasse MyView2rechts: R.styleable.MyView2_myattr1, falsch: R.styleable.MyView_myattr1)
vigilancer
27

Wie Priya Singhal antwortete, müssen für Android Studio die allgemeinen Attributnamen in ihrem eigenen Stilnamen definiert werden. Sie können nicht mehr an der Wurzel sein.

Es gibt jedoch noch ein paar andere Dinge zu beachten (weshalb ich auch eine Antwort hinzufüge):

  • Die gängigen Stile müssen nicht wie eine Ansicht benannt werden. (Dank dieser Antwort für den Hinweis.)
  • Sie müssen keine Vererbung mit einem Elternteil verwenden.

Beispiel

Folgendes habe ich kürzlich in einem Projekt mit zwei benutzerdefinierten Ansichten getan, die beide dieselben Attribute aufweisen. Solange die benutzerdefinierten Ansichten noch die Namen für die Attribute haben und keine enthalten format, kann ich weiterhin wie gewohnt über Code darauf zugreifen.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- common attributes to all custom text based views -->

    <declare-styleable name="TextAttributes">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <!-- custom text views -->

    <declare-styleable name="View1">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Optimiertes Beispiel

Tatsächlich muss ich die Attribute nicht einmal unter einen benutzerdefinierten Namen setzen. Solange ich sie formatfür mindestens eine benutzerdefinierte Ansicht definiere (geben Sie ihnen ein ), kann ich sie überall verwenden (ohne die format). Das funktioniert also auch (und sieht sauberer aus):

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="View1">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Bei einem großen Projekt kann dies jedoch unübersichtlich werden, und es ist möglicherweise besser, sie oben an einem einzigen Ort zu definieren (wie hier empfohlen ).

Suragch
quelle
Was ist los mit Vererbung? Ich habe benutzerdefinierte Ansichtshierarchien, deren zugehörige Stilelemente diese Beziehung nicht widerspiegeln. Dies kann nur in den zugehörigen Stildefinitionen durch Namenskonventionen und die darin definierten spezifischen Elemente abgeleitet werden (wobei zu beachten ist, dass einige zu einem Stil und einige zu einem anderen gehören). Ich möchte es lieber mit dem parentAttribut explizit machen, habe aber nicht viele Beiträge gesehen, die auf seine Verwendung hinweisen.
Samis
@samis, ich habe eine Weile nicht daran gearbeitet, aber ich weiß nichts falsch mit der Verwendung parent. Ich glaube, ich habe nur gesagt, dass es nicht erforderlich ist.
Suragch
Es ist nicht erforderlich, ich habe nur eine weitere Unterklasse erstellt, die um ein zusätzliches Attribut gewickelt ist, das ich nicht in die Basisklasse einfügen wollte. Ich verwende nur Kommentare und Namenskonventionen, um die Trennung anzuzeigen.
Samis
7

Vielen Dank, Lewis, ich hatte das gleiche Problem, und Ihre Vererbungslösung gab mir den Hinweis, es wie unten zu tun, und es funktioniert einwandfrei. Ich habe oben nur allgemeine Attribute deklariert und es ohne Formatierung erneut in den Textkörper der Stildeklaration geschrieben. Ich hoffe es hilft jemandem

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- common attributes -->
     <attr name="myattr1" format="string" />
     <attr name="myattr2" format="dimension" />

 <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
<declare-styleable name="MyView1" >
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myBackgroundColor" format="color"/>
</declare-styleable>

<!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
<declare-styleable name="MyView2" parent="MyView">
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myfont" format="string"/>
    ...
</declare-styleable>

Hanieh Variani
quelle
1

Nur für den Fall, dass jemand nach dem Versuch einer verfügbaren Lösung immer noch an diesem Problem festhält. Ich blieb beim Hinzufügen eines subtitleAttributs mit stringFormat.

Meine Lösung ist das Entfernen des Formats.

Vor:

<attr name="subtitle" format="string"/>

nach dem:

<attr name="subtitle"/>

Ahmad Muzakki
quelle