Création de vues composées sur Android

Lors de la création d'applications complexes, vous souhaiterez souvent réutiliser le même groupe de vues à différents endroits de l'application. Une façon de résoudre ce problème consiste à créer une vue encapsulant la logique et la disposition d'un groupe de vues afin que vous puissiez les réutiliser sans dupliquer le code à différents endroits du projet. Dans ce didacticiel, vous apprendrez à utiliser des vues composées pour créer des vues personnalisées facilement réutilisables..

1. Introduction

Sur Android, une vue composée d'un groupe de vues s'appelle une vue composée ou un composant composé. Dans ce didacticiel, vous allez créer un contrôle pour sélectionner une valeur dans une liste qui défile d'un côté à l'autre. Nous nommerons le composé spinner latéral car la vue par défaut du SDK Android permettant de choisir une valeur dans une liste s'appelle spinner. La capture d'écran suivante illustre ce que nous allons créer dans ce tutoriel..

2. Configuration du projet

Pour commencer, vous devez créer un nouveau projet Android avec Android 4.0 comme niveau de SDK minimum requis. Ce projet doit contenir uniquement une activité vide appelée Activité principale. le Activité ne fait rien d'autre qu'initialiser la mise en page comme vous pouvez le voir dans l'extrait de code suivant.

Classe publique MainActivity étend Activity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); 

La mise en page pour Activité principale est situé dans le /res/layout/activity_main.xml fichier et il ne devrait contenir qu'un vide Disposition relative dans lequel la vue composée sera affichée plus tard.

 

3. Créer une vue composée

Pour créer une vue composée, vous devez créer une nouvelle classe qui gère les vues dans la vue composée. Pour le côté spinner, vous avez besoin de deux Bouton vues pour les flèches et un Affichage voir pour afficher la valeur sélectionnée.

Pour commencer, créez le /res/layout/sidespinner_view.xml fichier de mise en page que nous allons utiliser pour la classe spinner côté, en veillant à envelopper les trois vues dans un  étiquette.

 

Ensuite, nous devons créer le SideSpinner classe qui gonfle cette disposition et définit les flèches comme images d’arrière-plan pour les boutons. À ce stade, la vue composée ne fait rien car il n'y a rien à afficher pour le moment..

Classe publique SideSpinner étend LinearLayout private Button mPreviousButton; bouton privé mNextButton; public SideSpinner (contexte de contexte) super (contexte); initializeViews (contexte);  public SideSpinner (contexte de contexte, AttributeSet attrs) super (contexte, attrs); initializeViews (contexte);  public SideSpinner (contexte de contexte, AttributeSet attrs, int defStyle) super (contexte, attrs, defStyle); initializeViews (contexte);  / ** * Gonfle les vues dans la disposition. * * @param context * le contexte actuel de la vue. * / private void initializeViews (contexte de contexte) LayoutInflater inflater = (LayoutInflater) contexte .getSystemService (Context.LAYOUT_INFLATER_SERVICE); inflater.inflate (R.layout.sidespinner_view, this);  @Override protected void onFinishInflate () super.onFinishInflate (); // Définit les images pour les boutons précédent et suivant. Utilise // les images intégrées pour que vous n'ayez pas besoin d'ajouter d'images, mais dans // une application réelle, vos images doivent être dans le package // d'application afin qu'elles soient toujours disponibles. mPreviousButton = (Bouton) this .findViewById (R.id.sidespinner_view_previous); mPreviousButton .setBackgroundResource (android.R.drawable.ic_media_previous); mNextButton = (Bouton) this .findViewById (R.id.sidespinner_view_next); mNextButton .setBackgroundResource (android.R.drawable.ic_media_next); 

Vous remarquerez que la vue composée étend la LinearLayout groupe de vue. Cela signifie que toute disposition utilisant la vue composée a accès aux attributs de la disposition linéaire. En conséquence, la présentation de la vue composée est un peu différente de la normale, la balise racine est un  balise au lieu de la balise pour un groupe de vues comme  ou .

Lorsque vous ajoutez la vue composée à la présentation de Activité principale, l'étiquette pour la vue composée agira en tant que  étiquette. Une classe de vue composée peut dériver de toute classe dérivant de ViewGroup, mais dans ce cas, la disposition linéaire est la plus appropriée car les vues sont disposées horizontalement.

4. Ajouter la vue composée à une mise en page

A ce stade, le projet est compilé mais rien n’est visible car la vue composée n’est pas dans la présentation de Activité principale. La vue spinner latérale doit être ajoutée à la présentation de l'activité comme toute autre vue. Le nom de la balise est le nom complet de la SideSpinner classe, y compris l'espace de noms.

Ajouter le spinner latéral à Activité principale, ajouter ce qui suit à la mise en page relative dans le /res/layout/activity_main.xml fichier.

Les attributs disponibles dans le balise sont des attributs de la mise en page linéaire depuis le SideSpinner la classe que nous avons créée étend la LinearLayout classe. Si vous lancez le projet, le cône latéral doit être visible, mais il ne contient pas encore de valeurs..

5. Ajouter des méthodes à la vue composée

Il manque encore quelques éléments si nous voulons réellement utiliser le cône latéral. Nous devrions pouvoir ajouter de nouvelles valeurs au cinéaste, sélectionner une valeur et obtenir la valeur sélectionnée.

Le moyen le plus simple d’ajouter de nouveaux comportements à une vue composée est d’ajouter de nouvelles méthodes publiques à la vue. SideSpinner classe. Ces méthodes peuvent être utilisées par n’importe quel Activité qui a une référence à la vue.

private CharSequence [] mSpinnerValues ​​= null; private int mSelectedIndex = -1; / ** * Définit la liste de valeurs dans le compteur, en sélectionnant la première valeur * par défaut. * * @param values ​​* les valeurs à définir dans le compteur. * / public void setValues ​​(CharSequence [] values) mSpinnerValues ​​= values; // Sélectionnez le premier élément du tableau de chaînes par défaut car // la liste de valeurs a été modifiée. setSelectedIndex (0);  / ** * Définit l'index sélectionné du compteur. * * @param index * l'index de la valeur à sélectionner. * / public void setSelectedIndex (int index) // Si aucune valeur n'est définie pour le compteur, ne faites rien. if (mSpinnerValues ​​== null || mSpinnerValues.length == 0) return; // Si la valeur d'index n'est pas valide, ne rien faire. si (index < 0 || index >= mSpinnerValues.length) return; // Définit l'index actuel et affiche la valeur. mSelectedIndex = index; TextView currentValue; currentValue = (TextView) this .findViewById (R.id.sidespinner_view_current_value); currentValue.setText (mSpinnerValues ​​[index]); // Si la première valeur est affichée, cache le bouton précédent. if (mSelectedIndex == 0) mPreviousButton.setVisibility (INVISIBLE); else mPreviousButton.setVisibility (VISIBLE); // Si la dernière valeur est affichée, cache le bouton suivant. if (mSelectedIndex == mSpinnerValues.length - 1) mNextButton.setVisibility (INVISIBLE); else mNextButton.setVisibility (VISIBLE);  / ** * Obtient la valeur sélectionnée du compteur ou null si aucun index * valide n'est encore défini. * * @retour la valeur sélectionnée du compteur. * / public CharSequence getSelectedValue () // Si aucune valeur n'est définie pour le compteur, retourne une chaîne vide. if (mSpinnerValues ​​== null || mSpinnerValues.length == 0) return ""; // Si l'index actuel n'est pas valide, retourne une chaîne vide. si (mSelectedIndex < 0 || mSelectedIndex >= mSpinnerValues.length) return ""; return mSpinnerValues ​​[mSelectedIndex];  / ** * Obtient l'index sélectionné du compteur. * * @retourne l'index sélectionné du compteur. * / public int getSelectedIndex () return mSelectedIndex; 

le onFinishInflate La méthode de la vue composée est appelée lorsque toutes les vues de la présentation sont gonflées et prêtes à être utilisées. C’est le lieu d’ajouter votre code si vous devez modifier des vues dans la vue composée..

Avec les méthodes que vous venez d’ajouter à la SideSpinner classe, le comportement des boutons sélectionnant les valeurs précédente et suivante peut maintenant être ajouté. Remplacer le code existant dans le onFinishInflate méthode avec ce qui suit:

@Override protected void onFinishInflate () // Lorsque les contrôles de la présentation sont en cours de gonflage, définissez // les rappels pour les flèches latérales. super.onFinishInflate (); // Lorsque vous appuyez sur le bouton précédent, sélectionnez la valeur // précédente dans la liste. mPreviousButton = (Bouton) this .findViewById (R.id.sidespinner_view_previous); mPreviousButton .setBackgroundResource (android.R.drawable.ic_media_previous); mPreviousButton.setOnClickListener (new OnClickListener () public void onClick (Afficher la vue) if (mSelectedIndex> 0) int newSelectedIndex = mSelectedIndex - 1; setSelectedIndex (newSelectedIndex);); // Lorsque l'utilisateur clique sur le bouton suivant, sélectionne l'élément suivant de la liste //. mNextButton = (Bouton) this .findViewById (R.id.sidespinner_view_next); mNextButton .setBackgroundResource (android.R.drawable.ic_media_next); mNextButton.setOnClickListener (new OnClickListener () public void onClick (vue d'affichage) if (mSpinnerValues! = null && mSelectedIndex < mSpinnerValues.length - 1)  int newSelectedIndex = mSelectedIndex + 1; setSelectedIndex(newSelectedIndex);   ); // Select the first value by default. setSelectedIndex(0); 

Avec le nouveau créé setValues et setSelectedIndex méthodes, nous pouvons maintenant initialiser le spinner côté de notre code. Comme pour toute autre vue, vous devez trouver la vue latérale dans la présentation avec le findViewById méthode. Nous pouvons ensuite appeler n'importe quelle méthode publique sur la vue à partir de l'objet renvoyé, y compris celles que nous venons de créer..

L’extrait de code suivant montre comment mettre à jour le onCreate méthode du Activité principale classe pour afficher une liste de valeurs dans la flèche latérale, en utilisant le setValues méthode. Nous pouvons également sélectionner la deuxième valeur de la liste par défaut en appelant le setSelectedIndex méthode.

Classe publique MainActivity étend Activity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Initialise le spinner latéral à partir du code. SideSpinner fruitsSpinner; fruitsSpinner = (SideSpinner) this .findViewById (R.id.sidespinner_fruits); CharSequence fruitList [] = "Pomme", "Orange", "Poire", "Raisins"; fruitsSpinner.setValues ​​(liste de fruits); fruitsSpinner.setSelectedIndex (1); 

Si vous lancez l'application, le cône latéral doit fonctionner comme prévu. La liste des valeurs est affichée et la valeur Orange est sélectionné par défaut.

6. Ajouter des attributs de mise en page à la vue composée

Les vues disponibles dans le SDK Android peuvent être modifiées via le code, mais certains attributs peuvent également être définis directement dans la présentation correspondante. Ajoutons un attribut à la roulette latérale qui définit les valeurs que cette dernière doit afficher..

Pour créer un attribut personnalisé pour la vue composée, nous devons d’abord définir cet attribut dans /res/values/attr.xml fichier. Chaque attribut de la vue composée doit être groupé dans un style avec un étiquette. Pour le cône latéral, le nom de la classe est utilisé comme indiqué ci-dessous.

    

dans le  tag, le prénom attribut contient l’identifiant utilisé pour faire référence au nouvel attribut dans la mise en page et le format attribut contient le type du nouvel attribut.

Pour la liste de valeurs, le référence type est utilisé car l'attribut fera référence à une liste de chaînes définies en tant que ressource. Les types de valeur normalement utilisés dans les modèles peuvent être utilisés pour vos attributs personnalisés, notamment booléenCouleurdimensionenumentierflotte et chaîne.

Voici comment définir la ressource pour une liste de chaînes que le valeurs attribut du côté spinner fera référence à. Il faut l'ajouter à la /res/values/strings.xml fichier comme indiqué ci-dessous.

  Concombre Patate Tomate Oignon Écraser  

Pour tester le nouveau valeurs attribuer, créer une vue latérale spinner dans la Activité principale disposition ci-dessous le spinner côté existant. L’attribut doit être préfixé par un espace de nom ajouté à la Disposition relative, tel que xmlns: sidespinner = "http://schemas.android.com/apk/res-auto". C'est ce que la mise en page finale /res/layout/activity_main.xml devrait ressembler.

   

Finalement, le SideSpinner la classe doit être modifiée pour lire le valeurs attribut. La valeur de chaque attribut de la vue est disponible dans le AttributeSet objet qui est passé en tant que paramètre du constructeur de la vue.

Pour obtenir la valeur de votre coutume valeurs attribut, nous appelons d’abord le obtenirStyledAttributes méthode du AttributeSet objet avec le nom du styleable contenant l'attribut. Ceci retourne la liste des attributs pour ce stylable en tant que TypedArray objet.

Nous appelons ensuite la méthode getter du TypedArray objet qui a le bon type pour l'attribut souhaité, en passant l'identificateur de l'attribut en tant que paramètre. Le bloc de code suivant montre comment modifier le constructeur du spinner latéral pour obtenir la liste des valeurs et les définir dans le spinner latéral.

public SideSpinner (contexte de contexte) super (contexte); initializeViews (contexte);  public SideSpinner (contexte de contexte, AttributeSet attrs) super (contexte, attrs); TypedArray typedArray; typedArray = contexte .obtainStyledAttributes (attrs, R.styleable.SideSpinner); mSpinnerValues ​​= typedArray .getTextArray (R.styleable.SideSpinner_values); typedArray.recycle (); initializeViews (contexte);  public SideSpinner (contexte de contexte, AttributeSet attrs, int defStyle) super (contexte, attrs, defStyle); TypedArray typedArray; typedArray = contexte .obtainStyledAttributes (attrs, R.styleable.SideSpinner); mSpinnerValues ​​= typedArray .getTextArray (R.styleable.SideSpinner_values); typedArray.recycle (); initializeViews (contexte); 

Si vous lancez l'application, vous devriez voir deux fileuses latérales qui fonctionnent indépendamment l'une de l'autre..

7. Enregistrer et restaurer l'état

La dernière étape que nous devons terminer consiste à enregistrer et à restaurer l'état de la vue composée. Lorsqu'une activité est détruite et recréée, par exemple lors de la rotation du périphérique, les valeurs des vues natives avec un identificateur unique sont automatiquement enregistrées et restaurées. Ce n'est actuellement pas vrai pour le côté spinner.

L'état des vues n'est pas enregistré. Les identifiants des vues dans la SideSpinner Les classes ne sont pas uniques car elles peuvent être réutilisées plusieurs fois. Cela signifie que nous sommes responsables de la sauvegarde et de la restauration des valeurs des vues dans la vue composée. Nous faisons cela en mettant en œuvre le onSaveInstanceState, onRestoreInstanceState, et dispatchSaveInstanceState méthodes. Le bloc de code suivant montre comment procéder pour le spinner latéral.

/ ** * Identifiant de l'état dans lequel enregistrer l'index * sélectionné du cône latéral. * / private static String STATE_SELECTED_INDEX = "SelectedIndex"; / ** * Identifiant de l'état de la super classe. * / private static String STATE_SUPER_CLASS = "SuperClass"; @Override protected Parcelable onSaveInstanceState () Bundle bundle = new Bundle (); bundle.putParcelable (STATE_SUPER_CLASS, super.onSaveInstanceState ()); bundle.putInt (STATE_SELECTED_INDEX, mSelectedIndex); retourner le paquet;  @Override protected void onRestoreInstanceState (état parcellisable) if (état de l'instance du groupe) Bundle bundle = (groupe) de l'état; super.onRestoreInstanceState (bundle .getParcelable (STATE_SUPER_CLASS)); setSelectedIndex (bundle.getInt (STATE_SELECTED_INDEX));  else super.onRestoreInstanceState (état);  @Override protected void dispatchSaveInstanceState (SparseArray container) // Vérifie que l'état des vues enfants du côté // spinner n'est pas enregistré car nous gérons l'état dans // onSaveInstanceState. super.dispatchFreezeSelfOnly (conteneur);  @Override protected void dispatchRestoreInstanceState (SparseArray container) // Vérifie que l'état des vues enfant du côté // spinner n'est pas restauré car nous gérons l'état dans // onSaveInstanceState. super.dispatchThawSelfOnly (conteneur); 

Conclusion

Le cône latéral est maintenant terminé. Les deux fileuses fonctionnent comme prévu et leurs valeurs sont restaurées si l'activité est détruite et recréée. Vous pouvez maintenant appliquer ce que vous avez appris pour réutiliser un groupe de vues dans une application Android à l'aide de vues composées..