Créer des composants de vue personnalisée

Essayer Compose
Jetpack Compose est le kit d'outils d'interface utilisateur recommandé pour Android. Découvrez comment utiliser les mises en page dans Compose.
<ph type="x-smartling-placeholder"></ph> Mises en page personnalisées dans Compose →

Android propose un modèle divisé en composants sophistiqué et puissant pour créer votre UI, basé sur les classes de mise en page fondamentales View et ViewGroup La plate-forme comprend diverses sous-classes View et ViewGroup prédéfinies, appelées widgets et mises en page, respectivement, que vous pouvez utiliser pour construire votre UI.

Voici une liste partielle des widgets disponibles : Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, et les fonctions AutoCompleteTextView, ImageSwitcher et TextSwitcher

Parmi les mises en page disponibles, citons LinearLayout, FrameLayout, RelativeLayout, et bien d'autres. Pour voir d'autres exemples, consultez Mises en page courantes.

Si aucun des widgets ou mises en page prédéfinis ne répond à vos besoins, vous pouvez créer les vôtres View. Si vous devez simplement apporter de petits ajustements à un widget existant ou vous pouvez sous-classer le widget ou la mise en page et remplacer ses méthodes.

En créant vos propres sous-classes View, vous pouvez contrôler précisément l'apparence et fonction d'un élément de l'écran. Pour vous donner une idée du contrôle que vous obtenez avec les vues personnalisées, voici Voici quelques exemples de ce que vous pouvez en faire:

  • Vous pouvez créer un type View entièrement personnalisé (par exemple, un "volume" "Contrôle" , rendue à l'aide de graphismes 2D, ressemblant à une commande électronique analogique.
  • Vous pouvez combiner un groupe de composants View en un seul composant, par exemple créer quelque chose comme une boîte combinée (combinaison d'une liste pop-up et d'un champ de saisie libre), un une commande de sélection à double volet (volet droit et volet gauche et droit avec une liste dans laquelle vous pouvez réattribuer l'élément dans chaque liste), et ainsi de suite.
  • Vous pouvez ignorer la façon dont un composant EditText s'affiche à l'écran. La <ph type="x-smartling-placeholder"></ph> L'application exemple NotePad s'en sert pour créer une page de bloc-notes bordée de lignes.
  • Vous pouvez capturer d'autres événements, comme les pressions sur les touches, et les gérer de manière personnalisée, par exemple que pour un jeu.

Les sections suivantes expliquent comment créer des vues personnalisées et les utiliser dans votre application. Pour des informations de référence détaillées, consultez la View.

Approche de base

Voici une vue d'ensemble de ce que vous devez savoir pour créer vos propres View. composants:

  1. Étendez une classe ou une sous-classe View existante avec votre propre classe.
  2. Ignorez certaines méthodes de la super-classe. Les méthodes de super-classe à remplacer commencent par on, par exemple onDraw(), onMeasure(), et onKeyDown() Ceci est semblable aux événements on de Activity ou ListActivity que vous pour les hooks de cycle de vie et d'autres fonctionnalités.
  3. Utilisez votre nouvelle classe d'extension. Une fois l'opération terminée, vous pouvez utiliser votre nouvelle classe d'extension à la place de la vue sur laquelle elle était basée.
<ph type="x-smartling-placeholder">

Composants entièrement personnalisés

Vous pouvez créer des composants graphiques entièrement personnalisés qui apparaissent voulez. Vous voulez peut-être un VU-mètre graphique qui ressemble à une ancienne jauge analogique, ou un affichage de texte qui vous permet de chanter à tue-tête. où une balle rebondissante se déplace le long des paroles à mesure que vous chantez, avec une machine à karaoké. Vous voudrez peut-être quelque chose que les composants intégrés ne peuvent pas faire, quelle que soit la façon dont vous les combinez.

Heureusement, vous pouvez créer des composants qui apparaissent et se comportent comme vous le souhaitez, en fonction de votre imagination, de la taille de l'écran et de la puissance de traitement disponible, en gardant à l'esprit que votre application peut devoir s'exécuter sur un appareil qui consomme beaucoup moins d'énergie que votre ordinateur de bureau station de travail.

Pour créer un composant entièrement personnalisé, tenez compte des points suivants:

  • La vue la plus générique que vous pouvez étendre est View. Vous commencez donc généralement par l'étendre pour créer un super composant.
  • Vous pouvez fournir un constructeur, qui peut récupérer des attributs et des paramètres du fichier XML, et vous pouvez utiliser vos propres attributs et paramètres, tels que la couleur et la plage du VU-mètre ou la largeur et l'amortissement de l'aiguille.
  • Vous souhaitez probablement créer vos propres écouteurs d'événements, accesseurs et modificateurs de propriété, ainsi que un comportement plus sophistiqué dans votre classe de composant.
  • Vous souhaiterez probablement ignorer onMeasure(). Vous devrez probablement aussi remplacez onDraw() si vous souhaitez que le composant affiche quelque chose. Bien que les deux aient le comportement par défaut, le onDraw() par défaut n'a aucun effet, et le comportement par défaut onMeasure() définit toujours une taille de 100 x 100, ce qui n'est probablement pas souhaitable.
  • Si nécessaire, vous pouvez également remplacer d'autres méthodes on.

Étendre onDraw() et onMeasurement()

La méthode onDraw() fournit Canvas sur laquelle vous pouvez Vous pouvez implémenter tout ce que vous souhaitez: graphismes 2D, autres composants standards ou personnalisés, texte stylisé ou toute autre chose à laquelle vous pensez.

<ph type="x-smartling-placeholder">

onMeasure() est un peu plus complexe. onMeasure() est un élément essentiel du contrat de rendu entre votre composant et son conteneur. onMeasure() doit être remplacés pour générer des rapports efficaces et précis sur les mesures des parties qu'il contient. C'est peut être légèrement plus complexe par les exigences de limite du parent, qui sont transmises à onMeasure(), et par l'obligation d'appeler la méthode setMeasuredDimension() avec la largeur et la hauteur mesurées une fois qu'elles sont calculé. Si vous n'appelez pas cette méthode à partir d'une méthode onMeasure() remplacée, génère une exception au moment de la mesure.

Dans les grandes lignes, l'implémentation de onMeasure() se présente comme suit:

  • La méthode onMeasure() remplacée est appelée avec la largeur et la hauteur. , qui sont considérées comme des exigences relatives aux restrictions de largeur et de hauteur les mesures que vous produisez. widthMeasureSpec et heightMeasureSpec sont tous deux des codes entiers représentant des dimensions. Une référence complète au type de des restrictions imposées par ces spécifications sont disponibles dans la documentation de référence View.onMeasure(int, int) Cette documentation de référence explique également l'ensemble de l'opération de mesure.
  • La méthode onMeasure() de votre composant calcule une largeur et une hauteur de mesure, qui sont nécessaires pour afficher le composant. Elle doit essayer de respecter les spécifications transmises. même s'il peut les dépasser. Dans ce cas, le parent peut choisir quoi faire, y compris le découpage, le défilement, la génération d'une exception ou la demande à onMeasure() d'essayer à nouveau ; peut-être avec des spécifications de mesure différentes.
  • Lorsque la largeur et la hauteur sont calculées, appelez la méthode setMeasuredDimension(int width, int height) avec les valeurs calculées des mesures. À défaut, une exception est générée.

Voici un résumé des autres méthodes standards que le framework appelle des vues:

Catégorie Méthodes Description
Création Constructeurs Une forme du constructeur est appelée lorsque la vue est créée à partir du code et un formulaire appelé lorsque la vue est gonflée à partir d'un fichier de mise en page. La deuxième forme analyse et applique les attributs définis dans le fichier de mise en page.
onFinishInflate() Appelée après qu'une vue et tous ses enfants sont gonflés à partir d'un fichier XML
Mise en page onMeasure(int, int) Appelée pour déterminer les exigences de taille pour cette vue et toutes de ses enfants.
onLayout(boolean, int, int, int, int) Appelée lorsque cette vue doit attribuer une taille et une position à tous ses enfants.
onSizeChanged(int, int, int, int) Appelé lorsque la taille de cette vue est modifiée.
Dessin onDraw(Canvas) Appelé lorsque la vue doit afficher son contenu.
Traitement des événements onKeyDown(int, KeyEvent) Appelée lorsqu'un événement de touche Bas se produit.
onKeyUp(int, KeyEvent) Appelé lorsqu'un événement "touche montante" se produit.
onTrackballEvent(MotionEvent) Appelé lorsqu'un événement de mouvement du trackball se produit.
onTouchEvent(MotionEvent) Appelé en cas de mouvement de l'écran tactile.
Mise au point onFocusChanged(boolean, int, Rect) Appelé lorsque la vue gagne ou perd le focus.
onWindowFocusChanged(boolean) Appelé lorsque la fenêtre contenant la vue est sélectionnée ou perdue.
Association... onAttachedToWindow() Appelé lorsque la vue est associée à une fenêtre.
onDetachedFromWindow() Appelé lorsque la vue est détachée de sa fenêtre.
onWindowVisibilityChanged(int) Appelé lorsque la visibilité de la fenêtre contenant la vue est modifiée.

Commandes composées

Si vous ne souhaitez pas créer un composant entièrement personnalisé, mais que vous un composant réutilisable constitué d'un groupe de commandes existantes, pour créer un composant (ou un contrôle composé) sont préférables. En résumé, cela rassemble un certain nombre des contrôles ou des vues atomiques en un groupe logique d'éléments pouvant être traités comme une seule chose. Par exemple, une boîte combinée peut être la combinaison d'un champ EditText d'une seule ligne. et un bouton adjacent avec une liste pop-up jointe. Si l'utilisateur appuie sur le bouton et sélectionne quelque chose dans la liste, le champ EditText est renseigné, mais ils peuvent aussi saisir du texte directement dans EditText s'ils le souhaitent.

Dans Android, deux autres vues sont déjà disponibles pour effectuer cette opération: Spinner et AutoCompleteTextView Quoi qu'il en soit, ce concept de liste déroulante en est un bon exemple.

Pour créer un composant composé, procédez comme suit:

  • Comme pour un Activity, utilisez l'approche déclarative (basée sur XML) pour créer les composants contenus ou les imbriquer par programmation à partir de votre code. La point de départ habituel est un Layout. Vous devez donc créer une classe qui étend une Layout Dans le cas d'une boîte combinée, vous pouvez utiliser un LinearLayout avec soit à l'horizontale. Vous pouvez imbriquer d'autres mises en page à l'intérieur afin que le composant composé puisse être arbitrairement complexe et structuré.
  • Dans le constructeur de la nouvelle classe, prenez les paramètres attendus par la super-classe et transmettez au constructeur de super-classe. Vous pouvez ensuite configurer les autres vues à utiliser dans votre nouveau composant. C'est ici que vous allez créer le champ EditText. liste. Vous pouvez introduire vos propres attributs et paramètres dans le code XML que votre peut extraire et utiliser.
  • Si vous le souhaitez, vous pouvez créer des écouteurs pour les événements que les vues contenues peuvent générer. Par exemple, pour l'écouteur de clics de l'élément de liste afin de mettre à jour le contenu de EditText si une sélection de liste est effectuée.
  • Vous pouvez également créer vos propres propriétés avec des accesseurs et des modificateurs. Par exemple, laissez au La valeur EditText doit être définie initialement dans le composant et rechercher son contenu lorsque nécessaires.
  • Si vous le souhaitez, remplacez onDraw() et onMeasure(). Cela n'est généralement pas nécessaire lorsque Extension d'une Layout, car la mise en page a un comportement par défaut qui fonctionne probablement bien.
  • Vous pouvez aussi remplacer d'autres méthodes on, comme onKeyDown(), par exemple pour choisir certaines les valeurs par défaut dans la liste contextuelle d'une liste déroulante lorsque l'utilisateur appuie sur une touche.

L'utilisation d'un Layout comme base d'un contrôle personnalisé présente des avantages, dont les suivantes:

  • Vous pouvez spécifier la mise en page à l'aide des fichiers XML déclaratifs, comme avec un écran d'activité, ou créer des vues par programmation et les imbriquer dans la mise en page à partir de votre code.
  • Les méthodes onDraw() et onMeasure(), ainsi que la plupart des autres on ont un comportement approprié. Vous n'avez donc pas besoin de les remplacer.
  • Vous pouvez rapidement construire des vues composées arbitrairement complexes et les réutiliser comme s'il s'agissait d'une un seul composant.

Modifier un type de vue existant

Si un composant est similaire à celui que vous souhaitez, vous pouvez l'étendre et remplacer le comportement que vous souhaitez modifier. Vous pouvez faire tout ce que vous faites avec un , mais en commençant par une classe plus spécialisée dans la hiérarchie View, vous pouvez d'obtenir sans frais un comportement qui fait ce que vous voulez.

Par exemple, Bloc-notes L'application exemple présente de nombreux aspects de l'utilisation de la plate-forme Android. Parmi eux, l'extension d'une Vue EditText pour créer un bloc-notes ligné. Cet exemple n'est pas parfait, et les API pour cela pourrait changer, mais cela démontre les principes.

Si vous ne l'avez pas déjà fait, importez l'exemple NotePad dans Android Studio ou examinez la à l'aide du lien fourni. Consultez en particulier la définition de LinedEditText. dans NoteEditor.java .

Voici quelques éléments à prendre en compte dans ce fichier:

  1. Définition

    La classe est définie à l'aide de la ligne suivante:
    public static class LinedEditText extends EditText

    LinedEditText est défini comme une classe interne dans NoteEditor. mais elle est publique afin qu'elle soit accessible en tant que NoteEditor.LinedEditText en dehors de la classe NoteEditor.

    De plus, LinedEditText est static, ce qui signifie qu'il ne génère pas ce que l'on appelle les "méthodes synthétiques" qui lui permettent d'accéder aux données de la classe parente. Cela signifie que se comporte comme une classe distincte et non comme un élément étroitement lié à NoteEditor. Il s'agit d'un moyen plus propre de créer des classes internes si elles n'ont pas besoin d'accéder à l'état depuis le externe. Cela réduit la taille de la classe générée et permet de l'utiliser facilement à partir d'autres classes.

    LinedEditText étend EditText, qui est la vue à personnaliser dans dans ce cas. Lorsque vous avez terminé, la nouvelle classe peut remplacer un EditText normal vue.

  2. Initialisation des classes

    Comme toujours, le super est appelé en premier. Il ne s'agit pas d'un constructeur par défaut, mais d'un paramétrée. Le EditText est créé avec ces paramètres lorsqu'il est gonflée à partir d'un fichier de mise en page XML. Le constructeur doit donc les prendre et les transmettre à le constructeur de super-classe.

  3. Méthodes de remplacement

    Cet exemple ne remplace que la méthode onDraw(), mais vous devrez peut-être remplacer à mesure que vous créez vos propres composants personnalisés.

    Pour cet exemple, le remplacement de la méthode onDraw() vous permet de peindre les lignes bleues sur la toile de la vue EditText. Le canevas est transmis à la classe onDraw(). La méthode super.onDraw() est appelée avant la méthode se termine. La méthode de super-classe doit être appelée. Dans ce cas, appelez-le à la fin après vous peignez les lignes que vous souhaitez inclure.

  4. Composant personnalisé

    Vous disposez désormais de votre composant personnalisé, mais comment pouvez-vous l'utiliser ? Dans l'exemple du bloc-notes, le le composant personnalisé est utilisé directement à partir de la mise en page déclarative. note_editor.xml dans la res/layout dossier:

    <view xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.example.android.notepad.NoteEditor$LinedEditText"
        android:id="@+id/note"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:padding="5dp"
        android:scrollbars="vertical"
        android:fadingEdge="vertical"
        android:gravity="top"
        android:textSize="22sp"
        android:capitalize="sentences"
    />
    

    Le composant personnalisé est créé en tant que vue générique dans le fichier XML, et la classe est spécifiée. en utilisant le package complet. La classe interne que vous définissez est référencée à l'aide de la méthode La notation NoteEditor$LinedEditText, qui est une méthode standard pour désigner la valeur interne dans le langage de programmation Java.

    Si votre composant de vue personnalisée n'est pas défini en tant que classe interne, vous pouvez déclarer la vue avec le nom de l'élément XML et excluant l'attribut class. Pour Exemple:

    <com.example.android.notepad.LinedEditText
      id="@+id/note"
      ... />
    

    Notez que la classe LinedEditText est désormais un fichier de classe distinct. Lorsque est imbriquée dans la classe NoteEditor, cette technique ne fonctionne pas.

    Les autres attributs et paramètres de la définition sont ceux qui sont transmis dans la de composant, puis transmis au constructeur EditText. il s'agit des mêmes paramètres que ceux utilisés pour une vue EditText. Il est possible d'ajouter vos propres paramètres.

La création de composants personnalisés n'est pas aussi compliquée que nécessaire.

Un composant plus sophistiqué peut remplacer encore plus de méthodes on et introduire sa ses propres méthodes d'assistance, en personnalisant sensiblement ses propriétés et son comportement. La seule limite votre imagination et ce que le composant doit faire pour le faire.