Attributi con lo stesso nome in attrs.xml per la visualizzazione personalizzata


180

Sto scrivendo alcune visualizzazioni personalizzate che condividono alcuni attributi con lo stesso nome. Nella rispettiva <declare-styleable>sezione in attrs.xmlMi piacerebbe usare gli stessi nomi per gli attributi:

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

Ricevo un errore a dirlo myattr1e myattr2sono già definiti. Ho scoperto che dovrei omettere l' formatattributo per myattr1e myattr2in MyView2, ma se lo faccio, ottengo il seguente errore nella console:

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

C'è un modo per farlo, forse una sorta di spaziatura dei nomi (solo indovinando)?

Risposte:


401

Soluzione: è sufficiente estrarre gli attributi comuni da entrambe le viste e aggiungerli direttamente come elementi figlio del <resources>nodo:

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

11
cosa succede quando myattr1string è in MyView1e integer in MyView2?
foxx1337,

4
Non credo, ad esempio possiamo avere l'attributo "orientamento" e per alcune viste è "orizzontale" / "verticale" e per altri "paesaggio" / "ritratto" / "quadrato". Dal mio punto di vista è un bug (o almeno un comportamento incoerente) in Android (tieni presente che: 1. gli attributi stylable iniziano sempre con prefisso = visualizza nome e 2. se crei progetti di libreria separati per tali viste tutto funzionerà bene )
se.solovyev il

4
Quando seguo questa risposta ottengo ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr Per tutto il punto di vista che cerco di dichiarare. Qualche idea?
Dapp,

45
@Google: Crappy design
Glenn Bech,

6
@ foxx1337 Basta usare <attr name="myattr1" format="string|integer" />. Per me va bene.
Mygod,

58

Sto pubblicando questa risposta perché la soluzione sopra pubblicata non ha funzionato per me in Android Studio. Devo condividere i miei attributi personalizzati tra le mie visualizzazioni personalizzate, quindi ho provato la soluzione sopra in Android Studio ma non ho avuto fortuna. Quindi esperimento e faccio un modo per farlo. Spero che possa aiutare qualcuno a cercare lo stesso problema.

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

Questo funziona per me completamente. Dobbiamo rendere lo stile di un genitore modificabile e quindi ereditare lo stile di un genitore. Ad esempio, come ho già fatto in precedenza: Nome di stile principale padre MyView e ereditato da questo mio altro stile di progettazione come MyView1 e MyView2 rispettivamente.


1
Questo ha funzionato per me. Non sono riuscito a trovare un modo per fare riferimento agli attributi estratti nel codice dalla risposta accettata.
Nemanja Kovacevic,

Hmm..questo è strano ... la soluzione accettata sembra funzionare bene per me (targetSdkVersion 27). Forse perché attributi come "testo" sono comuni e potrebbero essere esistiti in alcuni altri attrs.xml ..?
Aba,

Ho provato con un nome molto probabilmente insolito e la soluzione accettata ha funzionato ancora per me.
Aba,

Sono d'accordo con il primo commento! Non è possibile fare riferimento a un attr estratto da typedArray. Pertanto è necessario definire un genitore alla
moda

Per questo lavoro non dimenticate di affrontare questo attributo nel genitore e non nel bambino (per classe di MyView2destra: R.styleable.MyView2_myattr1, sbagliato: R.styleable.MyView_myattr1)
vigilancer

28

Come ha risposto Priya Singhal, Android Studio richiede che i nomi degli attributi comuni siano definiti all'interno del proprio nome di stile. Non possono più essere alla radice.

Tuttavia, ci sono un paio di altre cose da notare (motivo per cui sto anche aggiungendo una risposta):

  • Non è necessario che gli stili comuni vengano denominati come una vista. (Grazie a questa risposta per averlo sottolineato.)
  • Non è necessario utilizzare l'ereditarietà con un genitore.

Esempio

Ecco cosa ho fatto in un recente progetto che ha due viste personalizzate che condividono entrambi gli stessi attributi. Finché le viste personalizzate hanno ancora i nomi degli attributi e non includono a format, posso comunque accedervi normalmente dal codice.

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

Esempio semplificato

In effetti, non ho nemmeno bisogno di mettere gli attributi sotto un nome personalizzato. Finché li definisco (gli do un format) per almeno una vista personalizzata, posso usarli ovunque (senza format). Quindi funziona anche (e sembra più pulito):

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

Per un progetto di grandi dimensioni, tuttavia, questo potrebbe diventare confuso e definirli in alto in un'unica posizione potrebbe essere migliore (come raccomandato qui ).


Cosa c'è di sbagliato nell'eredità? Ho gerarchie di viste personalizzate i cui stili associati non riflettono questa relazione, che può essere dedotta solo nelle definizioni di stile associate mediante convenzioni di denominazione e gli elementi specifici ivi definiti (notando che alcuni appartengono a uno stile e pochi a un altro). Preferirei renderlo esplicito con l' parentattributo ma non ho visto molti post che suggeriscono che sia un utilizzo.
Samis,

@samis, non ci ho lavorato per un po ', ma non so nulla di sbagliato nell'uso parent. Penso che stavo solo dicendo che non era necessario.
Suragch,

Non è richiesto, ho appena creato un'altra sottoclasse racchiusa in un attributo aggiuntivo che non volevo inserire nella classe base. Sto solo usando commenti e convenzioni di denominazione per indicare la separazione.
Samis,

8

Grazie Lewis ho avuto lo stesso problema e la tua soluzione di ereditarietà mi ha dato il suggerimento di farlo come di seguito e funziona bene. Ho appena dichiarato gli attributi comuni sopra e riscritto di nuovo nel corpo della dichiarazione di stile senza formattazione. Spero che aiuti qualcuno

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


1

Nel caso in cui qualcuno ancora bloccato con questo problema dopo aver provato la soluzione disponibile. Ho bloccato con Aggiungi subtitleattributo con stringformato.

La mia soluzione è rimuovere il formato.

prima:

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

dopo:

<attr name="subtitle"/>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.