Mises en page dans Views

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.

Une mise en page définit la structure d'une interface utilisateur dans votre application, par exemple dans une activité. Tous les éléments de la mise en page sont créés à l'aide d'une hiérarchie d'objets View et ViewGroup. Un View dessine généralement quelque chose que l'utilisateur peut voir et interagir. Un ViewGroup est un conteneur invisible qui définit la structure de mise en page pour View et les autres objets ViewGroup, comme illustré dans la figure 1.

Figure 1. Illustration d'une hiérarchie des vues, qui définit une mise en page d'interface utilisateur.

Les objets View sont souvent appelés widgets et peuvent correspondre à l'une des nombreuses sous-classes, telles que Button ou TextView. Les objets ViewGroup sont généralement appelés mises en page et peuvent être de plusieurs types qui offrent une structure de mise en page différente, par exemple LinearLayout ou ConstraintLayout.

Vous pouvez déclarer une mise en page de deux manières:

  • Déclarez des éléments d'interface utilisateur au format XML. Android fournit un vocabulaire XML simple qui correspond aux classes et sous-classes View, comme celles des widgets et des mises en page. Vous pouvez également utiliser l'éditeur de mise en page d'Android Studio pour créer votre mise en page XML à l'aide d'une interface par glisser-déposer.

  • Instanciez les éléments de mise en page au moment de l'exécution. Votre application peut créer des objets View et ViewGroup, et manipuler leurs propriétés de manière programmatique.

La déclaration de votre UI au format XML vous permet de séparer la présentation de votre application du code qui contrôle son comportement. L'utilisation de fichiers XML permet également de fournir plus facilement différentes mises en page pour différentes tailles et orientations d'écran. Ce point est abordé plus en détail dans la section Assurer la compatibilité avec différentes tailles d'écran.

Le framework Android vous permet d'utiliser l'une de ces méthodes ou les deux pour créer l'interface utilisateur de votre application. Par exemple, vous pouvez déclarer les mises en page par défaut de votre application au format XML, puis modifier la mise en page au moment de l'exécution.

Écrire le code XML

Le vocabulaire XML d'Android vous permet de concevoir rapidement des mises en page d'interface utilisateur et les éléments qu'elles contiennent, de la même manière que vous créez des pages Web en HTML avec une série d'éléments imbriqués.

Chaque fichier de mise en page doit contenir exactement un élément racine, qui doit être un objet View ou ViewGroup. Après avoir défini l'élément racine, vous pouvez ajouter des objets de mise en page ou des widgets supplémentaires en tant qu'éléments enfants pour créer progressivement une hiérarchie View qui définit votre mise en page. Par exemple, voici une mise en page XML qui utilise un élément LinearLayout vertical pour contenir un élément TextView et un élément Button:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

Après avoir déclaré votre mise en page au format XML, enregistrez le fichier avec l'extension .xml dans le répertoire res/layout/ de votre projet Android afin qu'il se compile correctement.

Pour en savoir plus sur la syntaxe d'un fichier XML de mise en page, consultez la section Ressource de mise en page.

Charger la ressource XML

Lorsque vous compilez votre application, chaque fichier de mise en page XML est compilé dans une ressource View. Chargez la ressource de mise en page dans l'implémentation du rappel Activity.onCreate() de votre application. Pour ce faire, appelez setContentView() et transmettez-lui la référence à votre ressource de mise en page au format R.layout.layout_file_name. Par exemple, si votre mise en page XML est enregistrée sous main_layout.xml, chargez-la pour votre Activity comme suit:

Kotlin

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

Le framework Android appelle la méthode de rappel onCreate() dans votre Activity lors du lancement de l'Activity. Pour en savoir plus sur les cycles de vie des activités, consultez la section Présentation des activités.

Attributs

Chaque objet View et ViewGroup accepte sa propre variété d'attributs XML. Certains attributs sont spécifiques à un objet View. Par exemple, TextView accepte l'attribut textSize. Toutefois, ces attributs sont également hérités par les objets View qui étendent cette classe. Certains sont communs à tous les objets View, car ils sont hérités de la classe View racine, comme l'attribut id. Les autres attributs sont considérés comme des paramètres de mise en page. Ils décrivent certaines orientations de mise en page de l'objet View, telles que définies par l'objet ViewGroup parent de cet objet.

ID

Tout objet View peut être associé à un ID entier pour identifier de manière unique la View dans l'arborescence. Lorsque l'application est compilée, cet ID est référencé sous la forme d'un entier, mais il est généralement attribué dans le fichier XML de mise en page en tant que chaîne dans l'attribut id. Il s'agit d'un attribut XML commun à tous les objets View, qui est défini par la classe View. Vous l'utilisez très souvent. La syntaxe d'un ID dans une balise XML est la suivante:

android:id="@+id/my_button"

Le symbole at (@) au début de la chaîne indique que l'analyseur XML analyse et développe le reste de la chaîne d'ID, puis l'identifie en tant que ressource d'ID. Le symbole plus (+) signifie qu'il s'agit d'un nouveau nom de ressource qui doit être créé et ajouté à vos ressources dans le fichier R.java.

Le framework Android propose de nombreuses autres ressources d'ID. Lorsque vous faites référence à un ID de ressource Android, vous n'avez pas besoin du symbole plus, mais vous devez ajouter l'espace de noms du package android comme suit:

android:id="@android:id/empty"

L'espace de noms du package android indique que vous faites référence à un ID à partir de la classe de ressources android.R, et non à partir de la classe de ressources locale.

Pour créer des vues et les référencer à partir de votre application, vous pouvez utiliser un modèle commun, comme suit:

  1. Définissez une vue dans le fichier de mise en page et attribuez-lui un ID unique, comme dans l'exemple suivant :
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. Créez une instance de l'objet View et capturez-le à partir de la mise en page, généralement à l'aide de la méthode onCreate(), comme illustré dans l'exemple suivant:

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)
    

    Java

    Button myButton = (Button) findViewById(R.id.my_button);
    

Il est important de définir des ID pour les objets de vue lors de la création d'un RelativeLayout. Dans une mise en page relative, les vues sœurs peuvent définir leur mise en page par rapport à une autre vue sœur, référencée par l'ID unique.

Un identifiant n'a pas besoin d'être unique dans l'ensemble de l'arborescence, mais doit être unique dans la partie de l'arborescence que vous recherchez. Il peut souvent s'agir de l'arborescence entière. Il est donc préférable de la rendre unique lorsque cela est possible.

Paramètres de mise en page

Les attributs de mise en page XML nommés layout_something définissent les paramètres de mise en page de l'View adaptés au ViewGroup dans lequel il se trouve.

Chaque classe ViewGroup implémente une classe imbriquée qui étend ViewGroup.LayoutParams. Cette sous-classe contient des types de propriétés qui définissent la taille et la position de chaque vue enfant, en fonction du groupe de vues. Comme le montre la figure 2, le groupe de vues parent définit les paramètres de mise en page pour chaque vue enfant, y compris le groupe de vues enfant.

Figure 2 : Visualisation d'une hiérarchie des vues avec des paramètres de mise en page associés à chaque vue.

Chaque sous-classe LayoutParams possède sa propre syntaxe pour définir des valeurs. Chaque élément enfant doit définir une LayoutParams appropriée pour son parent, bien qu'il puisse également définir une LayoutParams différente pour ses propres enfants.

Tous les groupes de vues incluent une largeur et une hauteur, à l'aide de layout_width et layout_height, et chaque vue est nécessaire pour les définir. De nombreux éléments LayoutParams incluent des marges et des bordures facultatives.

Vous pouvez spécifier la largeur et la hauteur avec des mesures exactes, mais vous ne souhaiterez peut-être pas le faire souvent. Le plus souvent, utilisez l'une de ces constantes pour définir la largeur ou la hauteur:

  • wrap_content: indique à la vue de s'adapter aux dimensions requises par son contenu.
  • match_parent: indique à la vue de s'adapter à la taille du groupe de vues parent.

En général, nous vous déconseillons de spécifier une largeur et une hauteur de mise en page en utilisant des unités absolues telles que les pixels. Une meilleure approche consiste à utiliser des mesures relatives, telles que les unités de pixels indépendantes de la densité (dp), wrap_content ou match_parent, car elles permettent à votre application de s'afficher correctement sur différentes tailles d'écran. Les types de mesures acceptés sont définis dans la ressource de mise en page.

Position de la mise en page

Une vue présente une géométrie rectangulaire. Elle possède un lieu, exprimé par une paire de coordonnées gauche et en haut, et deux dimensions, exprimées par une largeur et une hauteur. L'unité utilisée pour l'emplacement et les dimensions est le pixel.

Vous pouvez récupérer l'emplacement d'une vue en appelant les méthodes getLeft() et getTop(). Le premier renvoie la coordonnée de gauche (x) du rectangle représentant la vue. Cette dernière renvoie la coordonnée supérieure (y) du rectangle représentant la vue. Ces méthodes renvoient l'emplacement de la vue par rapport à son parent. Par exemple, lorsque getLeft() renvoie 20, cela signifie que la vue se trouve à 20 pixels à droite du bord gauche de son parent direct.

En outre, il existe des méthodes pratiques pour éviter les calculs inutiles : getRight() et getBottom(). Ces méthodes renvoient les coordonnées des bords droit et inférieur du rectangle représentant la vue. Par exemple, l'appel de getRight() est semblable au calcul suivant: getLeft() + getWidth().

Taille, marge intérieure et marges

La taille d'une vue est exprimée à l'aide de la largeur et de la hauteur. Une vue a deux paires de valeurs de largeur et de hauteur.

La première paire est appelée largeur mesurée et hauteur mesurée. Ces dimensions définissent la taille souhaitée de la vue dans son élément parent. Vous pouvez obtenir les dimensions mesurées en appelant getMeasuredWidth() et getMeasuredHeight().

La deuxième paire est appelée width et height, ou parfois drawing width (largeur de dessin) et drawing height (hauteur de dessin). Ces dimensions définissent la taille réelle de la vue à l'écran, au moment du dessin et après la mise en page. Ces valeurs peuvent, mais ce n'est pas obligatoire, différer de la largeur et de la hauteur mesurées. Vous pouvez obtenir la largeur et la hauteur en appelant getWidth() et getHeight().

Pour mesurer ses dimensions, une vue tient compte de sa marge intérieure. La marge intérieure est exprimée en pixels pour les parties gauche, supérieure, droite et inférieure de la vue. Vous pouvez utiliser une marge intérieure pour décaler le contenu de la vue d'un nombre spécifique de pixels. Par exemple, une marge intérieure gauche de deux pousse le contenu de la vue de deux pixels vers la droite du bord gauche. Vous pouvez définir une marge intérieure à l'aide de la méthode setPadding(int, int, int, int), puis l'interroger en appelant getPaddingLeft(), getPaddingTop(), getPaddingRight() et getPaddingBottom().

Bien qu'une vue puisse définir une marge intérieure, elle n'est pas compatible avec les marges. Toutefois, les groupes de vues acceptent les marges. Pour en savoir plus, consultez ViewGroup et ViewGroup.MarginLayoutParams.

Pour en savoir plus sur les dimensions, consultez la section Dimension.

En plus de définir des marges et des marges intérieures de manière programmatique, vous pouvez également les définir dans vos mises en page XML, comme illustré dans l'exemple suivant:

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical" >
      <TextView android:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="16dp"
                android:padding="8dp"
                android:text="Hello, I am a TextView" />
      <Button android:id="@+id/button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="16dp"
              android:paddingBottom="4dp"
              android:paddingEnd="8dp"
              android:paddingStart="8dp"
              android:paddingTop="4dp"
              android:text="Hello, I am a Button" />
  </LinearLayout>
  

L'exemple précédent montre que la marge et le remplissage sont appliqués. Des marges et une marge intérieure uniformes sont appliquées tout autour de TextView, et Button montre comment les appliquer indépendamment aux différents bords.

Mises en page courantes

Chaque sous-classe de la classe ViewGroup fournit un moyen unique d'afficher les vues que vous imbriquez. Le type de mise en page le plus flexible, et celui qui fournit les meilleurs outils pour conserver une hiérarchie de mise en page superficielle, est ConstraintLayout.

Vous trouverez ci-dessous quelques-uns des types de mise en page courants intégrés à la plate-forme Android.

Créer une mise en page linéaire

Organise ses enfants en une seule ligne horizontale ou verticale et crée une barre de défilement si la longueur de la fenêtre dépasse celle de l'écran.

Créer des listes dynamiques

Lorsque le contenu de votre mise en page est dynamique ou non prédéterminé, vous pouvez utiliser RecyclerView ou une sous-classe de AdapterView. RecyclerView est généralement la meilleure option, car elle utilise la mémoire plus efficacement que AdapterView.

Voici les mises en page courantes possibles avec RecyclerView et AdapterView:

Liste

Affiche une liste déroulante à colonne unique.

Grille

Affiche une grille déroulante composée de colonnes et de lignes.

RecyclerView offre plus de possibilités et permet de créer un gestionnaire de mise en page personnalisé.

Remplir une vue d'adaptateur avec des données

Vous pouvez renseigner un élément AdapterView tel que ListView ou GridView en liant l'instance AdapterView à un élément Adapter, qui récupère des données à partir d'une source externe et crée un élément View qui représente chaque entrée de données.

Android fournit plusieurs sous-classes de Adapter utiles pour récupérer différents types de données et créer des vues pour une AdapterView. Les deux adaptateurs les plus courants sont les suivants:

ArrayAdapter
Utilisez cet adaptateur lorsque votre source de données est un tableau. Par défaut, ArrayAdapter crée une vue pour chaque élément du tableau en appelant toString() sur chaque élément et en plaçant le contenu dans un TextView.

Par exemple, si vous souhaitez afficher un tableau de chaînes dans un ListView, initialisez un nouveau ArrayAdapter à l'aide d'un constructeur pour spécifier la mise en page de chaque chaîne et du tableau de chaînes:

Kotlin

    val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
    

Java

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, myStringArray);
    

Les arguments de ce constructeur sont les suivants:

  • Votre application Context
  • Mise en page contenant une valeur TextView pour chaque chaîne du tableau
  • Le tableau de chaînes

Appelez ensuite setAdapter() sur votre ListView:

Kotlin

    val listView: ListView = findViewById(R.id.listview)
    listView.adapter = adapter
    

Java

    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(adapter);
    

Pour personnaliser l'apparence de chaque élément, vous pouvez remplacer la méthode toString() pour les objets de votre tableau. Pour créer une vue pour chaque élément autre qu'un élément TextView (par exemple, si vous souhaitez obtenir un ImageView pour chaque élément de tableau), étendez la classe ArrayAdapter et ignorez getView() afin de renvoyer le type d'affichage souhaité pour chaque élément.

SimpleCursorAdapter
Utilisez cet adaptateur lorsque vos données proviennent d'un Cursor. Lorsque vous utilisez SimpleCursorAdapter, spécifiez une mise en page à utiliser pour chaque ligne de Cursor et les colonnes de Cursor que vous souhaitez insérer dans les vues de la mise en page souhaitée. Par exemple, si vous souhaitez créer une liste de noms et de numéros de téléphone de personnes, vous pouvez effectuer une requête qui renvoie un Cursor contenant une ligne pour chaque personne et des colonnes pour les noms et les numéros. Vous créez ensuite un tableau de chaînes spécifiant les colonnes de Cursor à inclure dans la mise en page pour chaque résultat, ainsi qu'un tableau d'entiers spécifiant les vues correspondantes dans lesquelles chaque colonne doit être placée:

Kotlin

    val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME,
                              ContactsContract.CommonDataKinds.Phone.NUMBER)
    val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
    

Java

    String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER};
    int[] toViews = {R.id.display_name, R.id.phone_number};
    

Lorsque vous instanciez SimpleCursorAdapter, transmettez la mise en page à utiliser pour chaque résultat, l'élément Cursor contenant les résultats et les deux tableaux suivants:

Kotlin

    val adapter = SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0)
    val listView = getListView()
    listView.adapter = adapter
    

Java

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    ListView listView = getListView();
    listView.setAdapter(adapter);
    

SimpleCursorAdapter crée ensuite une vue pour chaque ligne de Cursor à l'aide de la mise en page fournie en insérant chaque élément fromColumns dans la vue toViews correspondante.

Si, au cours du cycle de vie de votre application, vous modifiez les données sous-jacentes lues par votre adaptateur, appelez notifyDataSetChanged(). Cela informe la vue associée que les données ont été modifiées, et qu'elle s'actualise.

Gérer les événements de clic

Vous pouvez répondre aux événements de clic sur chaque élément d'une AdapterView en implémentant l'interface AdapterView.OnItemClickListener. Par exemple :

Kotlin

listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // Do something in response to the click.
}

Java

// Create a message handling object as an anonymous class.
private OnItemClickListener messageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click.
    }
};

listView.setOnItemClickListener(messageClickedHandler);

Ressources supplémentaires

Découvrez comment les mises en page sont utilisées dans l'application de démonstration Sunflower sur GitHub.