MDC-101 Android: Principes de base de Material Components (MDC) (Java)

logo_components_color_2x_web_96dp.png

Material Components (MDC) aide les développeurs à implémenter Material Design. Conçu par une équipe d'ingénieurs et de spécialistes de l'expérience utilisateur travaillant pour Google, MDC propose des dizaines de composants d'interface utilisateur élégants et fonctionnels. Il est disponible pour Android, iOS, le Web et Flutter.

material.io/develop

Que sont Material Design et Material Components pour Android ?

Material Design est un système permettant de créer des produits numériques audacieux et esthétiques. Les équipes produit peuvent ainsi réaliser leurs meilleurs graphismes en combinant style, branding, interactions et animations selon des principes communs et des composants harmonieux.

Pour les applications Android, Material Components pour Android(MDC-Android) met une bibliothèque de composants au service du graphisme et de l'ingénierie afin d'assurer une expérience utilisateur homogène dans votre application. Ces composants sont mis à jour lorsque le système Material Design évolue afin de garantir une mise en œuvre homogène au pixel près et de respecter les normes de développement front-end de Google. MDC est également disponible pour le Web, iOS et Flutter.

Dans cet atelier de programmation, vous allez créer une page de connexion à l'aide de plusieurs composants de MDC-Android.

Objectifs de l'atelier

Cet atelier de programmation est le premier d'une série de quatre qui vous aideront à créer une application Android d'e-commerce appelée Shrine, dédiée à la vente de vêtements et d'articles pour la maison. Il vous montrera comment personnaliser les composants pour représenter n'importe quelle marque ou style à l'aide de MDC-Android.

Dans cet atelier de programmation, vous créerez une page de connexion pour Shrine contenant :

  • Deux champs de texte, un pour le nom d'utilisateur et l'autre pour un mot de passe
  • Deux boutons, l'un pour "Cancel" (Annuler) et l'autre pour "Next" (Suivant)
  • Le nom de l'application (Shrine)
  • Image du logo Shrine

Composants MDC-Android utilisés dans cet atelier de programmation

  • Champ de texte
  • Bouton

Prérequis

  • Connaissances de base sur le développement Android
  • Android Studio (téléchargez-le ici si vous ne l'avez pas déjà fait)
  • Un émulateur ou un appareil Android (disponible via Android Studio)
  • L'exemple de code (voir l'étape suivante)

Quel est votre niveau d'expérience en termes de création d'applications Android ?

Débutant Intermédiaire Expert

Démarrer Android Studio

Lorsque vous ouvrez Android Studio, une fenêtre de bienvenue s'affiche. Toutefois, si vous lancez Android Studio pour la première fois, suivez les étapes de l'assistant de configuration Android Studio en conservant les valeurs par défaut. Le téléchargement et l'installation des fichiers nécessaires peuvent prendre plusieurs minutes. Par conséquent, n'hésitez pas à passer à la section suivante en laissant ces opérations s'exécuter en arrière-plan.

Télécharger l'application de départ de l'atelier de programmation

Télécharger l'application de départ

Elle se trouve dans le répertoire material-components-android-codelabs-101-starter/java.

… ou cloner l'atelier depuis GitHub

Pour cloner cet atelier de programmation à partir de GitHub, exécutez les commandes suivantes :

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 101-starter

Charger le code de départ dans Android Studio

  1. Une fois l'assistant de configuration terminé et la fenêtre de bienvenue dans Android Studio affichée, cliquez sur Open an existing Android Studio project (Ouvrir un projet Android Studio existant). Accédez au répertoire dans lequel vous avez installé l'exemple de code, puis sélectionnez java > shrine(ou recherchez shrine sur votre ordinateur) pour ouvrir le projet Shrine.
  2. Attendez qu'Android Studio crée et synchronise le projet (voir les indicateurs d'activité situés en bas de la fenêtre Android Studio).
  3. À ce stade, Android Studio peut générer des erreurs de compilation, car vous ne disposez pas du SDK Android ni de certains outils de compilation, comme celui présenté ci-dessous. Suivez les instructions fournies dans Android Studio pour installer/mettre à jour ces éléments et synchroniser votre projet.

Ajouter des dépendances de projet

Le projet nécessite une dépendance à la bibliothèque de support MDC-Android. L'exemple de code que vous avez téléchargé devrait déjà inclure cette dépendance, mais il est recommandé de suivre les étapes suivantes pour en être sûr.

  1. Accédez au fichier build.gradle du module app et vérifiez si le bloc dependencies inclut bien une dépendance à MDC Android :
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (Facultatif) Si nécessaire, modifiez le fichier build.gradle pour ajouter les dépendances suivantes et synchroniser le projet.
dependencies {
    api 'com.google.android.material:material:1.1.0-alpha06'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:core:1.1.0'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test:runner:1.2.0-alpha05'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha05'
}

Exécuter l'application de départ

  1. Assurez-vous que la configuration de compilation indiquée à gauche du bouton d'exécution / de lecture est app.
  2. Appuyez sur le bouton vert pour créer et exécuter l'application.
  3. Dans la fenêtre Select Deployment Target (Sélectionner une cible de déploiement), si un de vos appareils Android figurent déjà dans la liste de ceux disponibles, passez à l'étape 8. Sinon, cliquez sur Create New Virtual Device (Créer un appareil virtuel).
  4. Sur l'écran Select Hardware (Sélectionner le matériel), sélectionnez un appareil (par exemple, Pixel 2), puis cliquez sur Next (Suivant).
  5. Sur l'écran System Image (Image système), sélectionnez une version récente d'Android (de préférence le niveau d'API le plus élevé). Sinon, cliquez sur le lien Télécharger qui s'affiche, puis procédez au téléchargement.
  6. Cliquez sur Next (Suivant).
  7. Sur l'écran Android Virtual Device (AVD) (Appareil virtuel Android), laissez les paramètres tels quels et cliquez sur Finish (Terminer).
  8. Sélectionnez un appareil Android dans la boîte de dialogue de la cible de déploiement.
  9. Cliquez sur OK.
  10. Android Studio crée l'application, la déploie et l'ouvre automatiquement sur l'appareil cible.

Opération réussie ! Le code de départ de la page de connexion de Shrine doit s'exécuter dans votre émulateur. Le nom "Shrine" et le logo Shrine devraient s'afficher.

Voyons à présent le code. Nous avons fourni un framework de navigation Fragment simple dans notre exemple de code pour afficher les fragments et naviguer entre eux.

Ouvrez MainActivity.java dans le répertoire shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine. Il doit contenir les éléments suivants :

MainActivity.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity implements NavigationHost {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.shr_main_activity);

       if (savedInstanceState == null) {
           getSupportFragmentManager()
                   .beginTransaction()
                   .add(R.id.container, new LoginFragment())
                   .commit();
       }
   }

   /**
    * Navigate to the given fragment.
    *
    * @param fragment       Fragment to navigate to.
    * @param addToBackstack Whether or not the current fragment should be added to the backstack.
    */
   @Override
   public void navigateTo(Fragment fragment, boolean addToBackstack) {
       FragmentTransaction transaction =
               getSupportFragmentManager()
                       .beginTransaction()
                       .replace(R.id.container, fragment);

       if (addToBackstack) {
           transaction.addToBackStack(null);
       }

       transaction.commit();
   }
}

Cette activité affiche le fichier de mise en page R.layout.shr_main_activity, défini dans shr_main_activity.xml.

Vous pouvez voir que dans onCreate(),, MainActivity.java démarre une transaction Fragment afin d'afficher le LoginFragment. LoginFragment., que nous allons modifier pour cet atelier de programmation. L'activité implémente également une méthode navigateTo(Fragment), définie dans NavigationHost, qui permet à n'importe quel fragment de naviguer vers un autre fragment.

Command+clic (ou Ctrl+clicshr_main_activity dans le fichier d'activité pour ouvrir le fichier de mise en page, ou accédez au fichier de mise en page dans app -> res -> layout -> shr_main_activity.xml.

shr_main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/container"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity" />

Ici, nous voyons un <FrameLayout> simple qui sert de conteneur pour tous les fragments affichés par l'activité. Ouvrons LoginFragment.java.

LoginFragment.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

/**
* Fragment representing the login screen for Shrine.
*/
public class LoginFragment extends Fragment {

   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment
       View view = inflater.inflate(R.layout.shr_login_fragment, container, false);

       // Snippet from "Navigate to the next Fragment" section goes here.

       return view;
   }

   // "isPasswordValid" from "Navigate to the next Fragment" section method goes here
}

LoginFragment gonfle le fichier de mise en page shr_login_fragment et l'affiche dans onCreateView(). Examinons le fichier de mise en page shr_login_fragment.xml pour voir à quoi ressemble la page de connexion.

shr_login_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@color/loginPageBackgroundColor"
   tools:context=".LoginFragment">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:clipChildren="false"
       android:clipToPadding="false"
       android:orientation="vertical"
       android:padding="24dp"
       android:paddingTop="16dp">

       <ImageView
           android:layout_width="64dp"
           android:layout_height="64dp"
           android:layout_gravity="center_horizontal"
           android:layout_marginTop="48dp"
           android:layout_marginBottom="16dp"
           app:srcCompat="@drawable/shr_logo" />

       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center_horizontal"
           android:layout_marginBottom="132dp"
           android:text="@string/shr_app_name"
           android:textAllCaps="true"
           android:textSize="16sp" />

       <!-- Snippet from "Add text fields" section goes here. -->

       <!-- Snippet from "Add buttons" section goes here. -->

   </LinearLayout>
</ScrollView>

Ici, nous pouvons voir un <LinearLayout> avec un <ImageView> en haut, représentant le logo "Shrine".

Ensuite, une balise <TextView> représente le libellé "SHRINE". Le texte de ce libellé est une ressource de chaîne nommée @string/shr_app_name. Si vous cliquez en appuyant sur la touche Cmd (ou Ctrl) sur le nom de la ressource de chaîne ou si vous ouvrez app -> res -> values -> strings.xml, vous pouvez voir le fichier strings.xml dans lequel les ressources de chaîne sont définies. Lorsque d'autres ressources de chaîne seront ajoutées à l'avenir, elles seront définies ici. Chaque ressource de ce fichier doit avoir un préfixe shr_ pour indiquer qu'elle fait partie de l'application Shrine.

Maintenant que vous connaissez le code de démarrage, vous pouvez implémenter le premier composant.

Pour commencer, nous allons ajouter à notre page de connexion deux champs de texte où les utilisateurs doivent saisir leur nom d'utilisateur et leur mot de passe. Nous utiliserons le composant MDC Text Field, qui inclut une fonctionnalité intégrée permettant d'afficher un libellé flottant et des messages d'erreur.

Ajouter le code XML

Dans shr_login_fragment.xml, ajoutez deux éléments TextInputLayout avec un élément enfant TextInputEditText à l'intérieur de <LinearLayout>, sous le libellé "SHRINE" <TextView> :

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="text"
       android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

L'extrait ci-dessus représente deux champs de texte, chacun composé d'un élément <TextInputLayout> et d'un enfant <TextInputEditText>. Le texte d'aide de chaque champ de texte est spécifié dans l'attribut android:hint.

Nous avons inclus deux nouvelles ressources de chaîne pour le champ de texte : @string/shr_hint_username et @string/shr_hint_password. Ouvrez strings.xml pour afficher ces ressources de chaîne.

strings.xml

...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...

Ajouter la validation des entrées

Les composants TextInputLayout fournissent une fonctionnalité de commentaires d'erreur intégrée.

Pour afficher les commentaires d'erreur, apportez les modifications suivantes à shr_login_fragment.xml :

  • Définissez l'attribut app:errorEnabled sur "true" dans l'élément Password TextInputLayout. Cela ajoutera une marge intérieure supplémentaire pour le message d'erreur sous le champ de texte.
  • Définissez l'attribut android:inputType sur "textPassword" dans l'élément Password TextInputEditText. Cela masquera le texte saisi dans le champ du mot de passe.

Une fois ces modifications apportées, les champs de texte de shr_login_fragment.xml devraient se présenter comme suit :

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="text"
       android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password"
   app:errorEnabled="true">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>

Essayez maintenant d'exécuter l'application. Une page s'affiche alors avec deux champs de texte, pour le nom d'utilisateur et le mot de passe.

Regardez l'animation du libellé flottant :

Nous allons ensuite ajouter deux boutons sur notre page de connexion : "Cancel" (Annuler) et "Next" (Suivant). Nous allons utiliser le composant MDC Button, qui est fourni avec l'effet Ripple d'encre emblématique de Material Design.

Ajouter le code XML

Dans shr_login_fragment.xml, ajoutez un <RelativeLayout> au <LinearLayout>, sous les éléments TextInputLayout. Ajoutez ensuite deux éléments <MaterialButton> à <RelativeLayout>.

Le fichier XML obtenu doit se présenter comme suit :

shr_login_fragment.xml

<RelativeLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <com.google.android.material.button.MaterialButton
       android:id="@+id/next_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentEnd="true"
       android:layout_alignParentRight="true"
       android:text="@string/shr_button_next" />

   <com.google.android.material.button.MaterialButton
       android:id="@+id/cancel_button"
       style="@style/Widget.MaterialComponents.Button.TextButton"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginEnd="12dp"
       android:layout_marginRight="12dp"
       android:layout_toStartOf="@id/next_button"
       android:layout_toLeftOf="@id/next_button"
       android:text="@string/shr_button_cancel" />

</RelativeLayout>

Et voilà ! Lorsque vous exécutez l'application, une ondulation d'encre s'affiche lorsque vous appuyez sur chaque bouton.

Enfin, nous ajouterons du code Java à LoginFragment.java pour relier notre bouton "SUIVANT" à un autre fragment. Vous remarquerez que chacun des composants que nous avons ajoutés à notre mise en page s'est vu attribuer un id. Nous utiliserons ces id pour référencer les composants dans notre code et ajouter des vérifications d'erreurs et une navigation.

Ajoutons une méthode booléenne privée isPasswordValid dans LoginFragment.java sous onCreateView(), avec une logique permettant de déterminer si le mot de passe est valide ou non. Dans cette démo, nous allons simplement nous assurer que le mot de passe comporte au moins huit caractères :

LoginFragment.java

/*
   In reality, this will have more complex logic including, but not limited to, actual
   authentication of the username and password.
*/
private boolean isPasswordValid(@Nullable Editable text) {
   return text != null && text.length() >= 8;
}

Ensuite, ajoutez un écouteur de clics au bouton "Suivant" qui définit et efface l'erreur en fonction de la méthode isPasswordValid() que nous venons de créer. Dans onCreateView(), cet écouteur de clics doit être placé entre la ligne de l'inflateur et la ligne return view.

Ensuite, ajoutons un écouteur de touches au mot de passe TextInputEditText pour écouter les événements de touches qui effaceraient l'erreur. Ce listener doit également utiliser isPasswordValid() pour vérifier si le mot de passe est valide. Vous pouvez l'ajouter directement sous l'écouteur de clics dans onCreateView().

Votre méthode onCreateView() devrait maintenant se présenter comme suit :

LoginFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment
   View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
   final TextInputLayout passwordTextInput = view.findViewById(R.id.password_text_input);
   final TextInputEditText passwordEditText = view.findViewById(R.id.password_edit_text);
   MaterialButton nextButton = view.findViewById(R.id.next_button);

   // Set an error if the password is less than 8 characters.
   nextButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           if (!isPasswordValid(passwordEditText.getText())) {
               passwordTextInput.setError(getString(R.string.shr_error_password));
           } else {
               passwordTextInput.setError(null); // Clear the error
           }
       }
   });

   // Clear the error once more than 8 characters are typed.
   passwordEditText.setOnKeyListener(new View.OnKeyListener() {
       @Override
       public boolean onKey(View view, int i, KeyEvent keyEvent) {
           if (isPasswordValid(passwordEditText.getText())) {
               passwordTextInput.setError(null); //Clear the error
           }
           return false;
       }
   });
   return view;
}            

Nous pouvons maintenant accéder à un autre fragment. Mettez à jour OnClickListener dans onCreateView() pour accéder à un autre fragment lorsque la validation des erreurs réussit. Pour ce faire, ajoutez la ligne suivante pour accéder à ProductGridFragment au cas else de l'écouteur de clics :

LoginFragment.java

...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...

Votre écouteur de clics devrait maintenant se présenter comme suit :

LoginFragment.java

...
MaterialButton nextButton = view.findViewById(R.id.next_button);

// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       if (!isPasswordValid(passwordEditText.getText())) {
           passwordTextInput.setError(getString(R.string.shr_error_password));
       } else {
           passwordTextInput.setError(null); // Clear the error
           ((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
       }
   }
});
...

Cette nouvelle ligne de code appelle la méthode navigateTo() à partir de MainActivity pour accéder à un nouveau fragment : ProductGridFragment. Il s'agit actuellement d'une page vide sur laquelle vous travaillerez dans MDC-102.

Maintenant, créez l'application. Appuyez sur le bouton "Suivant".

Bravo ! Cet écran constituera le point de départ de notre prochain atelier de programmation, sur lequel vous travaillerez dans MDC-102.

En utilisant un balisage XML de base et environ 30 lignes de code Java, la bibliothèque Material Components for Android vous a aidé à créer une belle page de connexion conforme aux consignes Material Design, et avec une apparence et un comportement cohérents sur tous les appareils.

Étapes suivantes

Les champs de texte et les boutons sont deux composants essentiels de la bibliothèque MDC-Android, mais il en existe bien d'autres. Vous pouvez explorer les autres composants de MDC-Android. Vous pouvez également accéder à l'atelier MDC-102 : Structure et mise en page Material Design pour en savoir plus sur la barre d'application supérieure, la vue Fiche et la mise en page en grille. Merci d'avoir essayé les composants Material. Nous espérons que cet atelier de programmation vous a plu.

La réalisation de cet atelier de programmation m'a demandé un temps et des efforts raisonnables

Tout à fait d'accord D'accord Ni d'accord, ni pas d'accord Pas d'accord Pas du tout d'accord

Je souhaite continuer à utiliser Material Components

Tout à fait d'accord D'accord Ni d'accord, ni pas d'accord Pas d'accord Pas du tout d'accord