Comment déclarer un élément d'interface utilisateur Android à l'aide de XML?
Comment déclarer un élément d'interface utilisateur Android à l'aide de XML?
Réponses:
Le Guide du développeur Android comporte une section intitulée Création de composants personnalisés . Malheureusement, la discussion sur les attributs XML ne couvre que la déclaration du contrôle dans le fichier de mise en page et non la gestion des valeurs dans l'initialisation de la classe. Les étapes sont les suivantes:
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>
Notez l'utilisation d'un nom non qualifié dans la declare-styleable
balise. Les attributs Android non standard comme le extraInformation
besoin de déclarer leur type. Les balises déclarées dans la superclasse seront disponibles dans les sous-classes sans avoir à être redéclarées.
Puisqu'il y a deux constructeurs qui utilisent un AttributeSet
pour l'initialisation, il est pratique de créer une méthode d'initialisation distincte pour les constructeurs à appeler.
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
est une int[]
ressource autogénérée où chaque élément est l'ID d'un attribut. Les attributs sont générés pour chaque propriété dans le XML en ajoutant le nom d'attribut au nom de l'élément. Par exemple, R.styleable.MyCustomView_android_text
contient l' android_text
attribut pour MyCustomView
. Les attributs peuvent ensuite être récupérés à l' TypedArray
aide de diverses get
fonctions. Si l'attribut n'est pas défini dans le défini dans le XML, il null
est renvoyé. Sauf, bien sûr, si le type de retour est une primitive, auquel cas le deuxième argument est renvoyé.
Si vous ne souhaitez pas récupérer tous les attributs, il est possible de créer ce tableau manuellement. L'ID pour les attributs Android standard est inclus dans android.R.attr
, tandis que les attributs pour ce projet sont dans R.attr
.
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
Veuillez noter que vous ne devez rien utiliser dans android.R.styleable
, selon ce fil, cela pourrait changer à l'avenir. Il est toujours dans la documentation car il est utile de visualiser toutes ces constantes au même endroit.
layout\main.xml
Incluez la déclaration d'espace de noms xmlns:app="http://schemas.android.com/apk/res-auto"
dans l'élément xml de niveau supérieur. Les espaces de noms fournissent une méthode pour éviter les conflits qui se produisent parfois lorsque différents schémas utilisent les mêmes noms d'élément (voir cet article pour plus d'informations). L'URL est simplement une manière d'identifier de manière unique les schémas - rien n'a réellement besoin d'être hébergé sur cette URL . Si cela ne semble rien faire, c'est parce que vous n'avez pas réellement besoin d'ajouter le préfixe d'espace de noms, sauf si vous devez résoudre un conflit.
<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"
/>
Référencez la vue personnalisée en utilisant le nom complet.
Si vous voulez un exemple complet, regardez l'exemple de vue d'étiquette 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"/>
Il est contenu dans un LinearLayout
avec un attribut namespace:xmlns:app="http://schemas.android.com/apk/res-auto"
Grande référence. Merci! Un ajout à cela:
S'il vous arrive d'avoir un projet de bibliothèque inclus qui a déclaré des attributs personnalisés pour une vue personnalisée, vous devez déclarer votre espace de noms de projet, pas celui de la bibliothèque. Par exemple:
Étant donné que la bibliothèque a le package "com.example.library.customview" et que le projet de travail a le package "com.example.customview", alors:
Ne fonctionnera pas (affiche l'erreur "error: Aucun identifiant de ressource trouvé pour l'attribut 'newAttr' dans le package '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" />
Marchera:
<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"
Voir commentaire 57 code.google.com/p/android/issues/detail?id=9656
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
parce que nous utilisons Android Studio et Gradle. Sinon (par exemple certaines versions d'Eclipse), cela se terminerait généralement par lib/[your package name]
. iehttp://schemas.android.com/apk/lib/[your package name]
Ajout à la réponse la plus votée.
Je veux ajouter quelques mots à propos de l'utilisation de obtenezStyledAttributes (), lorsque nous créons une vue personnalisée en utilisant des attributs prédéfinis android: xxx. Surtout lorsque nous utilisons TextAppearance.
Comme mentionné dans «2. Création de constructeurs», la vue personnalisée obtient AttributeSet lors de sa création. Utilisation principale que nous pouvons voir dans le code source 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();
Que pouvons-nous voir ici?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
L'ensemble d'attributs est traité par thème selon la documentation. Les valeurs d'attribut sont compilées étape par étape. Les premiers attributs sont remplis à partir du thème, puis les valeurs sont remplacées par des valeurs à partir du style, et enfin les valeurs exactes de XML pour une instance de vue spéciale remplacent les autres.
Tableau d'attributs demandés - com.android.internal.R.styleable.TextView
Il s'agit d'un tableau ordinaire de constantes. Si nous demandons des attributs standard, nous pouvons construire ce tableau manuellement.
Ce qui n'est pas mentionné dans la documentation - ordre des éléments TypedArray résultants.
Lorsque la vue personnalisée est déclarée dans attrs.xml, des constantes spéciales pour les index d'attribut sont générées. Et nous pouvons extraire des valeurs de cette façon: a.getString(R.styleable.MyCustomView_android_text)
. Mais pour le manuel int[]
il n'y a pas de constantes. Je suppose que getXXXValue (arrayIndex) fonctionnera bien.
Et une autre question est: "Comment pouvons-nous remplacer les constantes internes et demander des attributs standard?" Nous pouvons utiliser les valeurs android.R.attr. *.
Donc, si nous voulons utiliser l'attribut TextAppearance standard dans la vue personnalisée et lire ses valeurs dans le constructeur, nous pouvons modifier le code de TextView de cette façon:
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();
}
Où CustomLabel est défini:
<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>
Peut-être que je me trompe d'une manière ou d'une autre, mais la documentation Android sur obtenezStyledAttributes () est très pauvre.
Dans le même temps, nous pouvons simplement étendre le composant d'interface utilisateur standard, en utilisant tous ses attributs déclarés. Cette approche n'est pas si bonne, car TextView, par exemple, déclare beaucoup de propriétés. Et il sera impossible d'implémenter toutes les fonctionnalités dans onMeasure () et onDraw () remplacés.
Mais nous pouvons sacrifier une large réutilisation théorique du composant personnalisé. Dites «je sais exactement quelles fonctionnalités j'utiliserai» et ne partagez pas le code avec qui que ce soit.
Ensuite, nous pouvons implémenter le constructeur CustomComponent(Context, AttributeSet, defStyle)
. Après l'appel super(...)
, tous les attributs seront analysés et disponibles via les méthodes getter.
Il semble que Google ait mis à jour sa page développeur et y ait ajouté diverses formations.
L'un d'eux traite de la création de vues personnalisées et peut être trouvé ici
Merci beaucoup pour la première réponse.
Quant à moi, je n'ai eu qu'un seul problème avec ça. Lors du gonflage de ma vue, j'ai eu un bug: java.lang.NoSuchMethodException: MyView (Context, Attributes)
Je l'ai résolu en créant un nouveau constructeur:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
J'espère que cela vous aidera!
Vous pouvez inclure n’importe quel fichier de mise en page dans un autre fichier de mise en page.
<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>
ici, les fichiers de disposition dans la balise include sont d'autres fichiers de disposition .xml dans le même dossier res.