Come posso dichiarare un elemento dell'interfaccia utente Android usando XML?
Come posso dichiarare un elemento dell'interfaccia utente Android usando XML?
Risposte:
La Guida per gli sviluppatori Android ha una sezione chiamata Creazione di componenti personalizzati . Sfortunatamente, la discussione sugli attributi XML riguarda solo la dichiarazione del controllo all'interno del file di layout e non la gestione dei valori all'interno dell'inizializzazione della classe. I passi sono come segue:
values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="android:text"/>
<attr name="android:textColor"/>
<attr name="extraInformation" format="string" />
</declare-styleable>
</resources>
Si noti l'uso di un nome non qualificato nel declare-styleable
tag. Gli attributi Android non standard come extraInformation
devono essere dichiarati. I tag dichiarati nella superclasse saranno disponibili nelle sottoclassi senza dover essere nuovamente dichiarati.
Poiché ci sono due costruttori che usano un'inizializzazione AttributeSet
, è conveniente creare un metodo di inizializzazione separato che i costruttori possano chiamare.
private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.MyCustomView);
//Use a
Log.i("test",a.getString(
R.styleable.MyCustomView_android_text));
Log.i("test",""+a.getColor(
R.styleable.MyCustomView_android_textColor, Color.BLACK));
Log.i("test",a.getString(
R.styleable.MyCustomView_extraInformation));
//Don't forget this
a.recycle();
}
R.styleable.MyCustomView
è una int[]
risorsa generata automaticamente in cui ogni elemento è l'ID di un attributo. Gli attributi vengono generati per ogni proprietà nell'XML aggiungendo il nome dell'attributo al nome dell'elemento. Ad esempio, R.styleable.MyCustomView_android_text
contiene l' android_text
attributo per MyCustomView
. Gli attributi possono quindi essere recuperati TypedArray
utilizzando varie get
funzioni. Se l'attributo non è definito nel definito nell'XML, null
viene restituito. Tranne, ovviamente, se il tipo restituito è una primitiva, nel qual caso viene restituito il secondo argomento.
Se non vuoi recuperare tutti gli attributi, è possibile creare questo array manualmente. L'ID per gli attributi Android standard è incluso android.R.attr
, mentre gli attributi per questo progetto sono presenti R.attr
.
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
Si prega di notare che è necessario non usare nulla in android.R.styleable
, come da questa discussione potrebbe cambiare in futuro. È ancora nella documentazione come essere utile visualizzare tutte queste costanti in un unico punto.
layout\main.xml
Includi la dichiarazione dello spazio dei nomi xmlns:app="http://schemas.android.com/apk/res-auto"
nell'elemento xml di livello superiore. Gli spazi dei nomi forniscono un metodo per evitare i conflitti che a volte si verificano quando schemi diversi usano gli stessi nomi di elementi (vedi questo articolo per maggiori informazioni). L'URL è semplicemente un modo per identificare in modo univoco gli schemi - in realtà non è necessario ospitare nulla in quell'URL . Se questo non sembra fare nulla, è perché in realtà non è necessario aggiungere il prefisso dello spazio dei nomi a meno che non sia necessario risolvere un conflitto.
<com.mycompany.projectname.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="Test text"
android:textColor="#FFFFFF"
app:extraInformation="My extra information"
/>
Fare riferimento alla vista personalizzata utilizzando il nome completo.
Se vuoi un esempio completo, guarda l'esempio di visualizzazione dell'etichetta Android.
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
CharSequences=a.getString(R.styleable.LabelView_text);
<declare-styleable name="LabelView">
<attr name="text"format="string"/>
<attr name="textColor"format="color"/>
<attr name="textSize"format="dimension"/>
</declare-styleable>
<com.example.android.apis.view.LabelView
android:background="@drawable/blue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:text="Blue" app:textSize="20dp"/>
Questo è contenuto in a LinearLayout
con l'attributo namespace:xmlns:app="http://schemas.android.com/apk/res-auto"
Ottimo riferimento Grazie! Un'aggiunta ad esso:
Se ti capita di includere un progetto di biblioteca che ha dichiarato attributi personalizzati per una vista personalizzata, devi dichiarare il tuo spazio dei nomi del progetto, non quello della biblioteca. Per esempio:
Dato che la libreria ha il pacchetto "com.example.library.customview" e il progetto di lavoro ha il pacchetto "com.example.customview", quindi:
Non funzionerà (mostra l'errore "errore: nessun identificatore di risorsa trovato per l'attributo 'newAttr' nel pacchetto 'com.example.library.customview'"):
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="@+id/myView"
app:newAttr="value" />
Funzionerà:
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
android:id="@+id/myView"
app:newAttr="value" />
xmlns:app="http://schemas.android.com/apk/res-auto"
Vedi il commento 57 in code.google.com/p/android/issues/detail?id=9656
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
perché stiamo utilizzando Android Studio e Gradle. Altrimenti (ad esempio alcune versioni di Eclipse) di solito finisce lib/[your package name]
. vale a direhttp://schemas.android.com/apk/lib/[your package name]
Aggiunta alla risposta più votata.
Voglio aggiungere alcune parole sull'utilizzo di getStyledAttributes (), quando creiamo una vista personalizzata utilizzando gli attributi predefiniti android: xxx. Soprattutto quando usiamo TextAppearance.
Come menzionato in "2. Creazione di costruttori", la vista personalizzata ottiene AttributeSet alla sua creazione. Utilizzo principale che possiamo vedere nel codice sorgente di TextView (API 16).
final Resources.Theme theme = context.getTheme();
// TextAppearance is inspected first, but let observe it later
TypedArray a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
// huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();
Cosa possiamo vedere qui?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
Il set di attributi viene elaborato per tema in base alla documentazione. I valori degli attributi vengono compilati passo dopo passo. I primi attributi vengono riempiti dal tema, quindi i valori vengono sostituiti dai valori dallo stile e infine i valori esatti dall'XML per l'istanza della vista speciale sostituiscono gli altri.
Matrice di attributi richiesti: com.android.internal.R.styleable.TextView
è una matrice ordinaria di costanti. Se stiamo richiedendo attributi standard, possiamo creare questo array manualmente.
Cosa non è menzionato nella documentazione - ordine del risultato Elementi TypedArray.
Quando la vista personalizzata viene dichiarata in attrs.xml, vengono generate costanti speciali per gli indici degli attributi. E possiamo estrarre i valori in questo modo: a.getString(R.styleable.MyCustomView_android_text)
. Ma per il manuale int[]
non ci sono costanti. Suppongo che getXXXValue (arrayIndex) funzionerà bene.
E l'altra domanda è: "Come possiamo sostituire le costanti interne e richiedere attributi standard?" Possiamo usare i valori android.R.attr. *.
Quindi, se vogliamo usare l'attributo TextAppearance standard nella vista personalizzata e leggerne i valori nel costruttore, possiamo modificare il codice da TextView in questo modo:
ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
appearance =
theme.obtainStyledAttributes(apResourceId, new int[] { android.R.attr.textColor, android.R.attr.textSize,
android.R.attr.typeface, android.R.attr.textStyle });
}
if (appearance != null)
{
textColorApp = appearance.getColorStateList(0);
textSize = appearance.getDimensionPixelSize(1, textSize);
typefaceIndex = appearance.getInt(2, -1);
styleIndex = appearance.getInt(3, -1);
appearance.recycle();
}
Dove si definisce CustomLabel:
<declare-styleable name="CustomLabel">
<!-- Label text. -->
<attr name="android:text" />
<!-- Label text color. -->
<attr name="android:textColor" />
<!-- Combined text appearance properties. -->
<attr name="android:textAppearance" />
</declare-styleable>
Forse, mi sbaglio in qualche modo, ma la documentazione Android su getStyledAttributes () è molto scarsa.
Allo stesso tempo, possiamo semplicemente estendere il componente UI standard, usando tutti i suoi attributi dichiarati. Questo approccio non è così buono, perché TextView ad esempio dichiara molte proprietà. E sarà impossibile implementare la piena funzionalità in overriden onMeasure () e onDraw ().
Ma possiamo sacrificare l'ampio riutilizzo teorico del componente personalizzato. Dì "So esattamente quali funzionalità userò" e non condivido il codice con nessuno.
Quindi possiamo implementare il costruttore CustomComponent(Context, AttributeSet, defStyle)
. Dopo aver chiamato super(...)
avremo tutti gli attributi analizzati e disponibili attraverso metodi getter.
Sembra che Google abbia aggiornato la sua pagina degli sviluppatori e vi abbia aggiunto vari corsi di formazione.
Uno di questi riguarda la creazione di viste personalizzate e può essere trovato qui
Grazie mille per la prima risposta.
Quanto a me, ho avuto solo un problema. Quando gonfiavo la mia vista, avevo un bug: java.lang.NoSuchMethodException: MyView (Context, Attributes)
L'ho risolto creando un nuovo costruttore:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
Spero che questo possa aiutare!
Puoi includere qualsiasi file di layout in altri file di layout come-
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp" >
<include
android:id="@+id/frnd_img_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_imagefile"/>
<include
android:id="@+id/frnd_video_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_video_lay" />
<ImageView
android:id="@+id/downloadbtn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:src="@drawable/plus"/>
</RelativeLayout>
qui i file di layout nel tag include sono altri file di layout .xml nella stessa cartella res.