Thématisation Material avec Jetpack Compose

1. Avant de commencer

Material Design est un système de conception conçu et entretenu par des concepteurs et des développeurs de Google pour créer des expériences numériques de haute qualité pour Android, ainsi que pour d'autres plates-formes mobiles et Web. Vous y trouverez des consignes vous expliquant comment élaborer une application à l'interface lisible, attrayante et cohérente.

Dans cet atelier de programmation, vous allez apprendre à utiliser la thématisation Material, qui vous permet d'utiliser Material Design dans votre application, et découvrirez comment personnaliser les couleurs, la typographie et les formes. Vous pouvez personnaliser votre application autant que vous le souhaitez. Vous allez également apprendre à ajouter une barre d'application supérieure pour afficher le nom et l'icône de l'application.

Conditions préalables

  • Vous connaissez les bases du langage de programmation Kotlin, y compris la syntaxe, les fonctions et les variables.
  • Vous savez créer des mises en page dans Compose, y compris des lignes et des colonnes avec marge intérieure.
  • Vous savez créer des listes simples dans Compose.

Points abordés

  • Appliquer la thématisation Material à une application Compose.
  • Ajouter une palette de couleurs personnalisée à votre application.
  • Ajouter des polices personnalisées à votre application.
  • Ajouter des formes personnalisées aux éléments de votre application.
  • Ajouter une barre d'application supérieure à votre application.

Objectifs de l'atelier

  • Vous allez créer une application attrayante qui respecte les bonnes pratiques Material Design.

Ce dont vous avez besoin

  • La dernière version d'Android Studio.
  • Une connexion Internet pour télécharger le code de démarrage et les polices.

2. Présentation de l'application

Dans cet atelier de programmation, vous allez créer Woof, une application qui affiche une liste de chiens et utilise Material Design pour créer une expérience attractive dans l'application.

92eca92f64b029cf.png

Dans cet atelier de programmation, nous vous présenterons les possibilités offertes par la thématisation Material. Vous découvrirez également comment cette méthode pour améliorer l'apparence de vos prochaines applications.

Palette de couleurs

Vous trouverez ci-dessous les palettes de couleurs des thèmes clair et sombre que nous allons créer.

Cette image présente le jeu de couleurs clair de l'application Woof.

Cette image présente le jeu de couleurs sombre de l'application Woof.

Voici la version finale de l'application avec les deux thèmes.

Thème clair

Thème sombre

Typographie

Vous trouverez ci-dessous les polices que vous utiliserez dans l'application.

8ea685b3871d5ffc.png

Fichier du thème

Le fichier Theme.kt contient toutes les informations sur le thème de l'application, lequel est défini par des couleurs, des formes et une typographie. Il est important de garder ce fichier à l'esprit. Il se trouve le composable WoofTheme(), qui définit les couleurs, la typographie et les formes de l'application.

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Dans MainActivity.kt, WoofTheme() est ajouté pour fournir la thématisation Material à l'ensemble de l'application.

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           WoofTheme {
               Surface(
                   modifier = Modifier.fillMaxSize()
               ) {
                   WoofApp()
               }
           }
       }
   }
}

Examinez l'élément WoofPreview(). WoofTheme() a été ajouté pour ajouter la thématisation Material dans WoofPreview().

@Preview
@Composable
fun WoofPreview() {
    WoofTheme(darkTheme = false) {
        WoofApp()
    }
}

3. Télécharger le code de démarrage

Pour commencer, téléchargez le code de démarrage :

Vous pouvez également cloner le dépôt GitHub du code :

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout starter

Vous pouvez parcourir le code dans le dépôt GitHub Woof app.

Explorer le code de démarrage

  1. Ouvrez le code de démarrage dans Android Studio.
  2. Ouvrez com.example.woof > data > Dog.kt. Il contient le Dog data class qui sera utilisé pour représenter la photo, le nom, l'âge et les jeux préférés du chien. Il contient également une liste de chiens et les données que vous utiliserez dans votre application.
  3. Ouvrez res > drawable. Il contient tous les éléments image dont vous avez besoin pour ce projet, y compris l'icône de l'application, les images de chiens et les icônes.
  4. Ouvrez res > values > strings.xml. Il contient les chaînes que vous utilisez dans cette application, y compris le nom de l'appli, les noms des chiens, leur description et plus encore.
  5. Ouvrez MainActivity.kt. Ce code permet de créer une liste simple qui affiche la photo d'un chien, son nom et son âge.
  6. WoofApp() contient un élément LazyColumn qui affiche les éléments DogItem.
  7. DogItem() contient un élément Row qui affiche une photo du chien et des informations le concernant.
  8. DogIcon() affiche une photo du chien.
  9. DogInformation() affiche le nom et l'âge du chien.
  10. WoofPreview() vous permet d'afficher un aperçu de l'application dans le volet Design (Conception).

Assurez-vous que votre émulateur/appareil est en thème clair.

Dans cet atelier de programmation, vous allez utiliser les thèmes clair et sombre. Toutefois, la majorité de l'atelier est en thème clair. Avant de commencer, assurez-vous que votre appareil ou votre émulateur est réglé sur le thème clair.

Pour afficher le thème clair dans votre application, sur votre émulateur ou sur votre appareil physique :

  1. Accédez à l'application Paramètres de l'appareil.
  2. Recherchez l'option Thème sombre pour y accéder.
  3. Si le thème sombre est activé, désactivez-le.

Exécutez le code de démarrage pour découvrir votre point de départ. Il s'agit d'une liste qui affiche les différents chiens, avec leur photo, leur nom et leur âge. L'application est fonctionnelle, mais elle n'est pas parfaite. Nous allons donc y remédier.

6d253ae50c63014d.png

4. Ajouter une couleur

La première chose que vous allez modifier dans l'application Woof est le jeu de couleurs.

Il s'agit de la combinaison de couleurs utilisée par votre application. Les différentes combinaisons évoquent différentes émotions, ce qui a une influence sur la façon dont les utilisateurs se servent de votre application.

Dans le système Android, la couleur est représentée par une valeur hexadécimale (hex). Un code couleur hexadécimal commence par le caractère dièse (#), suivi de six lettres et/ou chiffres représentant les composants rouge, vert et bleu (RVB) de cette couleur. Les deux premières lettres/chiffres font référence au rouge, les deux caractères suivants au vert et les deux derniers au bleu.

Les nombres hexadécimaux utilisés pour créer les couleurs.

Une couleur peut également inclure une valeur alpha (lettres et/ou chiffres) qui définit la transparence de la couleur (#00 correspond à une opacité de 0 %, entièrement transparent ; #FF à une opacité de 100 %, entièrement opaque). Lorsqu'elle est incluse, la valeur alpha correspond aux deux premiers caractères du code hexadécimal. Si aucune valeur alpha n'est incluse, il s'agit par défaut de #FF, qui représente une opacité de 100 % (entièrement opaque).

Vous trouverez ci-dessous des exemples de couleurs ainsi que leurs valeurs hexadécimales.

2753d8cdd396c449.png

Utiliser Material Theme Builder pour créer un jeu de couleurs

Pour créer un jeu de couleurs personnalisé pour notre application, nous allons utiliser Material Theme Builder.

  1. Cliquez sur ce lien pour accéder à Material Theme Builder.
  2. Dans le volet de gauche, vous trouverez l'option "Core Colors" (Couleurs de base). Cliquez sur "Primary" (Couleur principale) :

Quatre couleurs principales dans Material Theme Builder

  1. Le sélecteur de couleur HCT s'ouvre.

Ce sélecteur HCT permet de choisir une couleur personnalisée dans Material Theme Builder.

  1. Pour créer le jeu de couleurs présenté sur les captures d'écran de l'application, vous devrez changer la couleur principale dans ce sélecteur. Dans la zone de texte, remplacez la valeur actuelle par #006C4C. La couleur principale de l'application devient verte.

Le sélecteur de couleur HCT affiche du vert.

Vous pouvez alors remarquer que les applications à l'écran se mettent à jour pour adopter un jeu de couleurs centré sur le vert.

Cette image montre les applications de Material Theme Builder réagissant à la modification de couleur du sélecteur HCT.

  1. Faites défiler la page. Le jeu de couleurs complet pour les thèmes clair et sombre est généré à partir de la couleur que vous avez choisie.

Thème clair dans Material Theme Builder

Thème sombre généré par Material Theme Builder

Vous vous demandez peut-être quels sont le rôle et le cas d'utilisation de chaque couleur. Voici de quoi éclairer votre lanterne :

  • Les couleurs principales sont utilisées pour les principaux composants de l'interface utilisateur.
  • Les couleurs secondaires sont utilisées pour les composants les moins visibles.
  • Les couleurs tertiaires sont utilisées pour accentuer le contraste des couleurs principales et secondaires, ou pour attirer davantage l'attention sur un élément, comme un champ de saisie.
  • Les éléments de couleur on apparaissent au-dessus des autres couleurs de la palette et sont principalement appliqués au texte, à l'iconographie et aux traits. Dans notre palette de couleurs, nous avons une couleur onSurface, qui apparaît au-dessus de la couleur de surface, et une couleur onPrimary, qui apparaît au-dessus de la couleur principale.

Ces encoches permettent d'harmoniser le système de conception, dans lequel les composants associés ont la même couleur.

Trêve de théorie des couleurs : il est temps d'ajouter cette magnifique palette à l'application !

Ajouter une palette de couleurs au thème

Sur la page de Material Theme Builder, vous pouvez cliquer sur le bouton Export (Exporter) pour télécharger un fichier Color.kt et un fichier Theme.kt avec le thème personnalisé que vous avez créé.

Ils permettront d'ajouter le thème personnalisé à votre application. Toutefois, comme le fichier Theme.kt généré n'inclut pas le code pour les couleurs dynamiques (dont nous parlerons plus tard dans cet atelier de programmation), vous devez copier les fichiers.

  1. Ouvrez le fichier Color.kt et remplacez son contenu par le code ci-dessous pour le copier dans le nouveau jeu de couleurs.
package com.example.woof.ui.theme

import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF006C4C)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFF89F8C7)
val md_theme_light_onPrimaryContainer = Color(0xFF002114)
val md_theme_light_secondary = Color(0xFF4D6357)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFCFE9D9)
val md_theme_light_onSecondaryContainer = Color(0xFF092016)
val md_theme_light_tertiary = Color(0xFF3D6373)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFC1E8FB)
val md_theme_light_onTertiaryContainer = Color(0xFF001F29)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFBFDF9)
val md_theme_light_onBackground = Color(0xFF191C1A)
val md_theme_light_surface = Color(0xFFFBFDF9)
val md_theme_light_onSurface = Color(0xFF191C1A)
val md_theme_light_surfaceVariant = Color(0xFFDBE5DD)
val md_theme_light_onSurfaceVariant = Color(0xFF404943)
val md_theme_light_outline = Color(0xFF707973)
val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED)
val md_theme_light_inverseSurface = Color(0xFF2E312F)
val md_theme_light_inversePrimary = Color(0xFF6CDBAC)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF006C4C)
val md_theme_light_outlineVariant = Color(0xFFBFC9C2)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFF6CDBAC)
val md_theme_dark_onPrimary = Color(0xFF003826)
val md_theme_dark_primaryContainer = Color(0xFF005138)
val md_theme_dark_onPrimaryContainer = Color(0xFF89F8C7)
val md_theme_dark_secondary = Color(0xFFB3CCBE)
val md_theme_dark_onSecondary = Color(0xFF1F352A)
val md_theme_dark_secondaryContainer = Color(0xFF354B40)
val md_theme_dark_onSecondaryContainer = Color(0xFFCFE9D9)
val md_theme_dark_tertiary = Color(0xFFA5CCDF)
val md_theme_dark_onTertiary = Color(0xFF073543)
val md_theme_dark_tertiaryContainer = Color(0xFF244C5B)
val md_theme_dark_onTertiaryContainer = Color(0xFFC1E8FB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF191C1A)
val md_theme_dark_onBackground = Color(0xFFE1E3DF)
val md_theme_dark_surface = Color(0xFF191C1A)
val md_theme_dark_onSurface = Color(0xFFE1E3DF)
val md_theme_dark_surfaceVariant = Color(0xFF404943)
val md_theme_dark_onSurfaceVariant = Color(0xFFBFC9C2)
val md_theme_dark_outline = Color(0xFF8A938C)
val md_theme_dark_inverseOnSurface = Color(0xFF191C1A)
val md_theme_dark_inverseSurface = Color(0xFFE1E3DF)
val md_theme_dark_inversePrimary = Color(0xFF006C4C)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFF6CDBAC)
val md_theme_dark_outlineVariant = Color(0xFF404943)
val md_theme_dark_scrim = Color(0xFF000000)
  1. Ouvrez le fichier Theme.kt et remplacez le contenu par le code ci-dessous pour ajouter les nouvelles couleurs au thème.
package com.example.woof.ui.theme

import android.app.Activity
import android.os.Build
import android.view.View
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val LightColors = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    onPrimaryContainer = md_theme_light_onPrimaryContainer,
    secondary = md_theme_light_secondary,
    onSecondary = md_theme_light_onSecondary,
    secondaryContainer = md_theme_light_secondaryContainer,
    onSecondaryContainer = md_theme_light_onSecondaryContainer,
    tertiary = md_theme_light_tertiary,
    onTertiary = md_theme_light_onTertiary,
    tertiaryContainer = md_theme_light_tertiaryContainer,
    onTertiaryContainer = md_theme_light_onTertiaryContainer,
    error = md_theme_light_error,
    errorContainer = md_theme_light_errorContainer,
    onError = md_theme_light_onError,
    onErrorContainer = md_theme_light_onErrorContainer,
    background = md_theme_light_background,
    onBackground = md_theme_light_onBackground,
    surface = md_theme_light_surface,
    onSurface = md_theme_light_onSurface,
    surfaceVariant = md_theme_light_surfaceVariant,
    onSurfaceVariant = md_theme_light_onSurfaceVariant,
    outline = md_theme_light_outline,
    inverseOnSurface = md_theme_light_inverseOnSurface,
    inverseSurface = md_theme_light_inverseSurface,
    inversePrimary = md_theme_light_inversePrimary,
    surfaceTint = md_theme_light_surfaceTint,
    outlineVariant = md_theme_light_outlineVariant,
    scrim = md_theme_light_scrim,
)

private val DarkColors = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    onPrimaryContainer = md_theme_dark_onPrimaryContainer,
    secondary = md_theme_dark_secondary,
    onSecondary = md_theme_dark_onSecondary,
    secondaryContainer = md_theme_dark_secondaryContainer,
    onSecondaryContainer = md_theme_dark_onSecondaryContainer,
    tertiary = md_theme_dark_tertiary,
    onTertiary = md_theme_dark_onTertiary,
    tertiaryContainer = md_theme_dark_tertiaryContainer,
    onTertiaryContainer = md_theme_dark_onTertiaryContainer,
    error = md_theme_dark_error,
    errorContainer = md_theme_dark_errorContainer,
    onError = md_theme_dark_onError,
    onErrorContainer = md_theme_dark_onErrorContainer,
    background = md_theme_dark_background,
    onBackground = md_theme_dark_onBackground,
    surface = md_theme_dark_surface,
    onSurface = md_theme_dark_onSurface,
    surfaceVariant = md_theme_dark_surfaceVariant,
    onSurfaceVariant = md_theme_dark_onSurfaceVariant,
    outline = md_theme_dark_outline,
    inverseOnSurface = md_theme_dark_inverseOnSurface,
    inverseSurface = md_theme_dark_inverseSurface,
    inversePrimary = md_theme_dark_inversePrimary,
    surfaceTint = md_theme_dark_surfaceTint,
    outlineVariant = md_theme_dark_outlineVariant,
    scrim = md_theme_dark_scrim,
)

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Dans WoofTheme(), colorScheme val utilise une instruction when.

  • Si dynamicColor est "true" et que la version de compilation est S ou ultérieure, le système vérifie si l'appareil est en darkTheme ou non.
  • Si c'est le cas et que le thème sombre est appliqué, colorScheme sera défini sur dynamicDarkColorScheme.
  • Dans le cas contraire, il sera défini sur dynamicLightColorScheme.
  • Si l'application n'utilise pas dynamicColor, le système vérifie la présence de darkTheme. Si c'est bien le thème sombre qui est appliqué, colorScheme sera défini sur DarkColors.
  • Si aucune de ces conditions n'est vraie, colorScheme est défini sur LightColors.

dynamicColor est défini sur "false" dans le fichier Theme.kt copié et les appareils sur lesquels nous travaillons sont en mode clair. colorScheme sera donc défini sur LightColors.

val colorScheme = when {
       dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
           val context = LocalContext.current
           if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
       }

       darkTheme -> DarkColors
       else -> LightColors
   }
  1. Exécutez à nouveau votre application. Notez que la barre d'application a automatiquement changé de couleur.

b48b3fa2ecec9b86.png

Mise en correspondance des couleurs

Les composants Material sont automatiquement mappés avec des encoches de couleur. D'autres composants clés de l'interface utilisateur, comme les boutons d'action flottants, sont définis par défaut sur la couleur primaire. Cela signifie que vous n'avez pas besoin d'attribuer explicitement une couleur à un composant. Le mappage sur une encoche de couleur est automatique lorsque vous définissez le thème dans votre application. Vous pouvez remplacer ce comportement en définissant explicitement une couleur dans le code. Cliquez ici pour savoir plus sur les rôles des couleurs.

Dans cette section, nous allons encapsuler le Row contenant DogIcon() et DogInformation() avec un élément Card pour différencier les couleurs des éléments de la liste avec l'arrière-plan.

  1. Dans la fonction composable DogItem(), encapsulez Row() avec une Card().
Card() {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Étant donné que le composable Card est désormais le premier élément enfant dans DogItem(), transmettez le modificateur DogItem() à Card, puis mettez à jour le modificateur de Row avec une nouvelle instance de Modifier.
Card(modifier = modifier) {
   Row(
       modifier = Modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Examinez l'élément WoofPreview(). Les éléments de la liste ont désormais changé automatiquement de couleur en raison des composables Card. Les couleurs sont attrayantes, mais il n'y a pas d'espace entre les éléments de la liste.

6d49372a1ef49bc7.png

Fichier Dimens

Tout comme vous utilisez le fichier strings.xml pour stocker les chaînes dans votre application, il est également recommandé d'utiliser un fichier nommé dimens.xml pour stocker les valeurs des dimensions. Cette approche vous permet de ne pas coder en dur les valeurs et, si nécessaire, de les modifier à partir d'un emplacement centralisé.

Accédez à app > res > values > dimens.xml, puis examinez le fichier. Il stocke les valeurs des dimensions pour padding_small, padding_medium et image_size. Ces dimensions seront utilisées dans toute l'application.

<resources>
   <dimen name="padding_small">8dp</dimen>
   <dimen name="padding_medium">16dp</dimen>
   <dimen name="image_size">64dp</dimen>
</resources>

Pour ajouter une valeur au fichier dimens.xml, utilisez le format suivant :

Image indiquant comment formater correctement les valeurs ajoutées à la ressource de dimension

Par exemple, pour ajouter padding_small, vous devez transmettre dimensionResource(id = R.dimen.padding_small).

  1. Dans WoofApp(), ajoutez un modifier avec padding_small dans l'appel de DogItem().
@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Dans WoofPreview(), l'espacement entre les éléments de liste est désormais plus clair.

c54f870f121fe02.png

Thème sombre

Sur Android, vous pouvez activer le thème sombre sur votre appareil. Ce thème utilise des couleurs plus sombres et plus discrètes, et présente les avantages suivants :

  • Il peut réduire considérablement la consommation d'énergie (selon la technologie d'écran de l'appareil).
  • Il améliore la visibilité pour les utilisateurs souffrant d'une déficience visuelle et ceux sensibles à la lumière vive.
  • Il permet à tous d'utiliser un appareil dans des conditions de faible luminosité.

Vous pouvez activer Forcer le mode sombre dans votre application pour que le système applique un thème sombre. Si vous forcez le thème sombre, vos utilisateurs bénéficient d'une meilleure expérience, ce qui vous permet de garder le contrôle du thème de l'application.

Lorsque vous choisissez votre propre thème sombre, notez que ses couleurs doivent respecter les normes d'accessibilité en matière de contraste. Ce type de thème utilise une couleur de surface sombre et limite les accentuations de couleur.

Afficher le thème sombre dans l'aperçu

Vous avez déjà ajouté les couleurs du thème sombre à l'étape précédente. Pour voir le thème sombre en action, vous devez ajouter un autre composable d'aperçu au fichier MainActivity.kt. Ainsi, lorsque vous modifiez la mise en page de l'interface utilisateur dans le code, vous pouvez voir simultanément à quoi ressemblent les thèmes clair et sombre.

  1. Sous WoofPreview(), créez une fonction appelée WoofDarkThemePreview() et annotez-la avec @Preview et @Composable.
@Preview
@Composable
fun WoofDarkThemePreview() {

}
  1. Dans DarkThemePreview(), ajoutez WoofTheme(). Sans WoofTheme(), vous ne verrez aucun des styles que nous avons ajoutés dans l'application. Attribuez la valeur true au paramètre darkTheme.
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {

   }
}
  1. Appelez WoofApp() dans WoofTheme().
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {
       WoofApp()
   }
}

Faites maintenant défiler le volet Design (Conception) pour voir l'application avec le thème sombre. L'arrière-plan est plus sombre pour l'application dans son ensemble et pour les éléments de liste, et le texte plus clair. Comparez les différences entre les thèmes sombre et clair.

Thème sombre

Thème clair

Afficher le thème sombre sur votre appareil ou votre émulateur

Pour afficher le thème sombre dans votre application, sur votre émulateur ou sur votre appareil physique :

  1. Accédez à l'application Paramètres de l'appareil.
  2. Recherchez l'option Thème sombre pour y accéder.
  3. Activez l'option Thème sombre.
  4. Rouvrez l'application Woof. Elle utilise le thème sombre.

bc31a94207265b08.png

Cet atelier de programmation porte davantage sur le thème clair. Avant de continuer, désactivez donc le thème sombre.

  1. Accédez à l'application Paramètres de l'appareil.
  2. Sélectionnez Affichage.
  3. Désactivez l'option Thème sombre.

Comparez l'apparence de l'application au début de la section et maintenant. Les éléments de liste et le texte sont plus définis, et le jeu de couleurs est plus esthétique.

Sans couleur

Avec couleur (thème clair)

Avec couleur (thème sombre)

Couleurs dynamiques

Material 3 se concentre fortement sur la personnalisation. L'une des nouvelles fonctionnalités de cette version est la couleur dynamique, qui crée un thème pour votre application en fonction du fond d'écran de l'utilisateur. Ainsi, si l'utilisateur aime le vert et que l'arrière-plan de son téléphone est bleu, l'application Woof s'affichera en bleu. La thématisation dynamique n'est disponible que sur certains appareils équipés d'Android 12 ou version ultérieure.

Vous pouvez utiliser un thème personnalisé pour les applications qui utilisent des couleurs percutantes, par exemple pour renforcer une identité de marque. Il s'agit également d'une bonne solution pour les appareils qui ne sont pas compatibles avec la thématisation dynamique.

  1. Pour activer la couleur dynamique, ouvrez le fichier Theme.kt, puis accédez au composable WoofTheme() et définissez le paramètre dynamicColor sur true.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = true,
   content: @Composable () -> Unit
)
  1. Pour modifier l'arrière-plan d'un appareil ou d'un émulateur, accédez aux Paramètres, puis recherchez Fond d'écran.
  2. Changez le fond d'écran pour utiliser une couleur ou un ensemble de couleurs.
  3. Réexécutez votre application pour afficher le thème dynamique (notez que votre appareil ou votre émulateur doit être équipé d'Android 12 ou version ultérieure). N'hésitez pas à tester cette fonctionnalité avec différents fonds d'écran.

710bd13f6b189dc5.png

  1. Cet atelier de programmation étant consacré aux thèmes personnalisés, désactivez dynamicColor avant de continuer.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = false,
   content: @Composable () -> Unit
)

5. Ajouter une forme

L'application d'une forme peut modifier considérablement l'apparence d'un composable. Les formes permettent de capter l'attention, d'identifier les composants, de communiquer un état et d'exprimer une image de marque.

De nombreuses formes sont définies à l'aide de RoundedCornerShape, qui décrit un rectangle avec des angles arrondis. Le nombre transmis définit l'arrondi des angles. Si vous utilisez RoundedCornerShape(0.dp), alors le rectangle n'a pas d'angles arrondis. Si vous utilisez RoundedCornerShape(50.dp), les angles sont entièrement arrondis.

0.dp

25.dp

50.dp

Dans l'application Woof, élément de liste avec mise en forme

Dans l'application Woof, élément de liste avec mise en forme

Dans l'application Woof, élément de liste avec mise en forme

Vous pouvez également personnaliser davantage les formes en ajoutant différents pourcentages d'arrondi à chaque angle. N'hésitez pas à faire quelques tests pour vous amuser !

En haut à gauche : 50.dp
En bas à gauche : 25.dp
En haut à droite : 0.dp
En bas à droite : 15.dp

En haut à gauche : 15.dp
En bas à gauche : 50.dp
En haut à droite : 50.dp
En bas à droite : 15.dp

En haut à gauche : 0.dp
En bas à gauche : 50.dp
En haut à droite : 0.dp
En bas à droite : 50.dp

Dans l'application Woof, élément de liste avec mise en forme

Dans l'application Woof, élément de liste avec mise en forme

Dans l'application Woof, élément de liste avec mise en forme

Le fichier Shape.kt est utilisé pour définir les formes des composants dans Compose. Il existe trois types de composants : petits, moyens et grands. Dans cette section, vous allez modifier le composant Card, qui est défini sur la taille medium. Les composants sont regroupés en catégories de formes en fonction de leur taille.

Dans cette section, vous appliquerez une forme arrondie à l'image du chien et modifierez la forme de l'élément de la liste.

Appliquer une forme arrondie à l'image de chien

  1. Ouvrez le fichier Shape.kt et notez que le paramètre "small" est défini sur RoundedCornerShape(50.dp). C'est ce qui permet de donner une forme de cercle à l'image.
val Shapes = Shapes(
   small = RoundedCornerShape(50.dp),
)
  1. Ouvrez MainActivity.kt. Dans DogIcon(), ajoutez un attribut clip au modifier de Image. L'image sera découpée selon ces instructions. Transmettez MaterialTheme.shapes.small.
import androidx.compose.ui.draw.clip

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),

Lorsque vous regardez WoofPreview(), vous remarquerez que les icônes des chiens sont arrondies. Certaines photos sont cependant coupées sur les côtés, et la forme n'est pas pleinement arrondie.

1d4d1e5eaaddf71e.png

  1. Pour arrondir les angles des photos, ajoutez un attribut ContentScale et un attribut Crop. L'image rentre maintenant dans le cadre arrondi. Notez que contentScale est un attribut de Image, et ne fait pas partie de modifier.
import androidx.compose.ui.layout.ContentScale

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),
       contentScale = ContentScale.Crop,

Voici le composable DogIcon() complet :

@Composable
fun DogIcon(
    @DrawableRes dogIcon: Int,
    modifier: Modifier = Modifier
) {
    Image(
        modifier = modifier
            .size(dimensionResource(R.dimen.image_size))
            .padding(dimensionResource(R.dimen.padding_small))
            .clip(MaterialTheme.shapes.small),
        contentScale = ContentScale.Crop,
        painter = painterResource(dogIcon),

        // Content Description is not needed here - image is decorative, and setting a null content
        // description allows accessibility services to skip this element during navigation.

        contentDescription = null
    )
}

Dans WoofPreview(), les icônes sont maintenant circulaires.

fc93106990f5e161.png

Appliquer une forme aux éléments de liste

Dans cette section, vous appliquerez une forme aux éléments de liste. Ils sont déjà affichés via un élément Card. Une Card est une surface qui peut contenir un seul composable et contient des options de décoration. Il est possible d'ajouter de la décoration en utilisant une bordure, une forme et bien plus. Dans cette section, vous utiliserez une Card pour appliquer une forme à un élément de liste.

Dans l'application Woof, élément de liste avec des dimensions de forme ajoutées.

  1. Ouvrez le fichier Shape.kt. Card est un composant de type "medium". Vous devez donc ajouter le paramètre correspondant de l'objet Shapes. Pour cette application, nous allons arrondir les coins supérieur droit et inférieur gauche de chaque élément de liste, mais pas complètement. Pour ce faire, transmettez la valeur 16.dp à l'attribut medium.
medium = RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp)

Étant donné qu'un élément Card utilise déjà par défaut la forme moyenne, vous n'avez pas besoin de la définir explicitement. Consultez l'aperçu pour voir la Card avec sa nouvelle forme !

Aperçu de l'application Woof avec des éléments Card mis en forme

Si vous revenez au fichier Theme.kt dans WoofTheme() et que vous examinez MaterialTheme(), vous constaterez que l'attribut shapes est défini sur la val Shapes que vous venez de mettre à jour.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Vous trouverez ci-dessous un aperçu des éléments de liste, avant et après la mise en forme. Comme vous pouvez le constater, les formes rendent l'application plus attrayante.

Sans mise en forme

Avec mise en forme

6. Ajouter une typographie

L'échelle de type Material Design

Une échelle de type est une sélection de styles de police pouvant être utilisés dans une application pour garantir un style flexible mais cohérent. L'échelle de type Material Design comprend 15 styles de police compatibles avec ce système. La dénomination et le regroupement ont été simplifiés pour les affichages, les titres principaux, les titres, le corps de texte et les libellés, avec des tailles grandes, moyennes et petites pour chaque catégorie. N'utilisez ces choix que si vous souhaitez personnaliser votre application. Si vous ne savez pas quoi définir pour les catégories d'échelle de type, vous pouvez utiliser une échelle de typographie par défaut.

999a161dcd9b0ec4.png

L'échelle de type contient des catégories de texte réutilisables, dont chacune a une utilisation et une signification spécifiques.

Affichage

S'agissant des éléments textuels les plus grands à l'écran, les styles d'affichage sont réservés au texte ou aux chiffres courts et importants. Ils sont mieux adaptés aux grands écrans.

Titre principal

Les titres principaux sont particulièrement adaptés aux textes courts à forte intensité sur les écrans plus petits. Ces styles permettent d'introduire des passages principaux du texte ou des zones de contenu importantes.

Titre

Les titres sont plus petits que les styles de titre principal et doivent être utilisés pour les textes d'accentuation relativement courts.

Corps

Les styles de corps sont utilisés pour les passages de texte plus longs dans votre application.

Libellé

Les styles de libellé sont plus petits et fonctionnels. Ils sont utilisés pour le texte à l'intérieur des composants ou pour le texte de taille réduite dans le corps du contenu, comme les sous-titres.

Polices

La plate-forme Android propose différentes polices, mais vous pouvez utiliser une police non fournie par défaut pour personnaliser votre application. Les polices personnalisées apportent une touche personnelle et peuvent être utilisées pour le branding.

Dans cette section, vous ajouterez les polices personnalisées Abril Fatface, Montserrat Bold et Montserrat Regular. Vous allez utiliser les titres displayLarge et displayMedium ainsi que le corps de texte bodyLarge, tous issus du système de types Material. Vous devrez les ajouter au texte de votre application.

Créer une police pour le répertoire de ressources Android

Avant d'ajouter des polices à votre application, vous devez ajouter un répertoire de polices.

  1. Dans la vue Projet d'Android Studio, faites un clic droit sur le dossier res.
  2. Sélectionnez New > Android Resource Directory (Nouveau > Répertoire des ressources Android).

Cette image montre comment accéder à la structure de fichiers dans le répertoire de ressources Android.

  1. Nommez le répertoire font, définissez le type de ressource sur font, puis cliquez sur OK.

Cette image montre comment ajouter un répertoire de police à l'aide du nouveau répertoire de ressources.

  1. Ouvrez votre nouveau répertoire de ressources de police sous res > font.

Télécharger des polices personnalisées

Puisque vous utilisez des polices qui ne sont pas fournies par la plate-forme Android, vous devez télécharger les polices personnalisées.

  1. Accédez à https://fonts.google.com/.
  2. Recherchez Montserrat, puis cliquez sur Download family (Télécharger la famille).
  3. Décompressez le fichier ZIP.
  4. Ouvrez le dossier Montserrat téléchargé. Dans le dossier static, recherchez Montserrat-Bold.ttf et Montserrat-Regular.ttf. L'acronyme TTF signifie "TrueType Font" (police TrueType) : il s'agit du format des fichiers de police. Sélectionnez les deux polices, puis faites-les glisser vers le répertoire de ressources de police de votre projet Android Studio.

Cette image montre le contenu du dossier statique des polices Montserrat.

  1. Dans votre dossier de polices, renommez Montserrat-Gold.ttf en montserrat_bold.ttf, et renommez Montserrat-Standard.ttf en montserrat_regular.ttf.
  2. Recherchez Abril Fatface et cliquez sur Download family (Télécharger la famille).
  3. Ouvrez le dossier Abril_Fatface téléchargé. Sélectionnez le fichier AbrilFatface-Regular.ttf et faites-le glisser dans le répertoire de ressources de police.
  4. Dans votre dossier de police, remplacez le nom du fichier Abril_Fatface_Regular.ttf par abril_fatface_regular.ttf.

Voici à quoi devrait ressembler le répertoire de ressources de polices dans votre projet, avec les trois fichiers de police personnalisée :

Cette image montre les fichiers de police ajoutés au dossier correspondant.

Initialiser les polices

  1. Dans la fenêtre du projet, ouvrez ui.theme > Type.kt. Initialisez les polices téléchargées sous les instructions d'importation et au-dessus de la val Typography. Pour commencer, initialisez Abril Fatface en la définissant sur FontFamily, puis transmettez Font avec le fichier de police abril_fatface_regular.
​​import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import com.example.woof.R

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)
  1. Initialisez Montserrat sous Abril Fatface en la définissant sur FontFamily et en transmettant Font avec le fichier de police montserrat_regular. Pour montserrat_bold, incluez également FontWeight.Bold. Même si vous transmettez la version "bold" (gras) du fichier de police, Compose ne sait pas que le fichier est en gras. Vous devez donc explicitement associer le fichier à FontWeight.Bold.
import androidx.compose.ui.text.font.FontWeight

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)

val Montserrat = FontFamily(
   Font(R.font.montserrat_regular),
   Font(R.font.montserrat_bold, FontWeight.Bold)
)

Ensuite, définissez les différents types de titres en fonction des polices que vous venez d'ajouter. L'objet Typography comporte des paramètres pour 13 caractères différents, décrits ci-dessus. Vous pouvez en définir autant que nécessaire. Dans cette appli, nous allons définir displayLarge, displayMedium et bodyLarge. Dans la partie suivante, vous utiliserez labelSmall, donc nous allons également l'ajouter ici.

Vous trouverez ci-dessous un tableau indiquant la police, l'épaisseur et la taille de chaque titre ajouté.

8ea685b3871d5ffc.png

  1. Définissez la valeur de l'attribut displayLarge sur la valeur TextStyle, puis saisissez les informations du tableau ci-dessus dans les champs fontFamily, fontWeight et fontSize. Autrement dit, tout le texte défini sur displayLarge utilisera la police Abril Fatface, avec une épaisseur de police normale et une propriété fontSize de 36.sp.

Répétez ces étapes pour displayMedium, labelSmall et bodyLarge.

import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.sp

val Typography = Typography(
   displayLarge = TextStyle(
       fontFamily = AbrilFatface,
       fontWeight = FontWeight.Normal,
       fontSize = 36.sp
   ),
   displayMedium = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 20.sp
   ),
   labelSmall = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 14.sp
   ),
   bodyLarge = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Normal,
       fontSize = 14.sp
   )
)

Si vous accédez au fichier Theme.kt dans WoofTheme() et que vous examinez MaterialTheme(), le paramètre typography est égal à Typography val, que vous venez de mettre à jour.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Appliquer une typographie au texte de l'application

Vous allez maintenant ajouter les types de titres à chaque instance de texte dans l'application.

  1. Ajoutez le style displayMedium pour dogName, car il s'agit d'une information courte et importante. Ajoutez le style bodyLarge pour dogAge : il est particulièrement adapté aux tailles de texte plus petites.
@Composable
fun DogInformation(
   @StringRes dogName: Int,
   dogAge: Int,
   modifier: Modifier = Modifier
) {
   Column(modifier = modifier) {
       Text(
           text = stringResource(dogName),
           style = MaterialTheme.typography.displayMedium,
           modifier = Modifier.padding(top = dimensionResource(id = R.dimen.padding_small))
       )
       Text(
           text = stringResource(R.string.years_old, dogAge),
           style = MaterialTheme.typography.bodyLarge
       )
   }
}
  1. À présent, dans WoofPreview(), le nom du chien s'affiche en police Montserrat, en gras et en taille 20.sp, tandis que son âge s'affiche en police Montserrat normale en taille 14.sp.

Aperçu de l'application Woof avec les espaces vides

Vous trouverez ci-dessous un aperçu des éléments de liste, avant et après l'ajout de la typographie. Notez la différence de police entre le nom du chien et son âge.

Sans typographie

Avec typographie

7. Ajouter une barre supérieure

Un Scaffold, ou échafaudage, est une mise en page qui fournit des emplacements pour divers composants et éléments sur l'écran, tels que Image, Row ou Column. Un Scaffold fournit également un emplacement pour TopAppBar, que vous utiliserez dans cette section.

La TopAppBar peut être utilisée de plusieurs façons, mais dans ce cas, elle vous permettra de créer une image de marque et de donner une touche personnelle à votre application. Il existe quatre types de TopAppBar différents : centré, petit, moyen et grand. Dans cet atelier de programmation, vous allez implémenter une barre d'application supérieure centrée. Vous allez créer un composable qui ressemble à la capture d'écran ci-dessous, et l'insérer dans la section topBar d'un Scaffold.

172417c7b64372f7.png

Pour cette application, la barre supérieure se compose d'un Row avec un logo et du texte qui correspond au nom de l'application. Le logo inclut une petite patte en dégradé de couleur et le titre de l'application.

736f411f5067e0b5.png

Ajouter une image et du texte à la barre supérieure

  1. Dans MainActivity.kt, créez un composable appelé WoofTopAppBar(). Si vous le souhaitez, vous pouvez lui ajouter un modifier.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {

}
  1. Scaffold prend en charge le paramètre contentWindowInsets, qui permet de spécifier des encarts pour le contenu de l'échafaudage. WindowInsets correspond aux parties de l'écran où votre application peut rentrer en conflit avec l'UI du système. Elles doivent être transmises à l'emplacement de contenu via les paramètres PaddingValues. En savoir plus.

La valeur contentWindowInsets est transmise à LazyColumn en tant que contentPadding.

@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}
  1. Dans Scaffold, ajoutez un attribut topBar et définissez-le sur WoofTopAppBar().
Scaffold(
   topBar = {
       WoofTopAppBar()
   }
)

Voici à quoi ressemble le composable WoofApp() :

@Composable
fun WoofApp() {
    Scaffold(
        topBar = {
            WoofTopAppBar()
        }
    ) { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Rien n'a changé dans WoofPreview(), car WoofTopAppBar() est vide. Remédions à ce problème.

Aperçu de l'application Woof avec la typographie

  1. Dans WoofTopAppBar() Composable, ajoutez CenterAlignedTopAppBar() et définissez le paramètre modificateur sur celui transmis dans WoofTopAppBar().
import androidx.compose.material3.CenterAlignedTopAppBar

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       modifier = modifier
   )
}
  1. Pour le paramètre de titre, transmettez un Row qui contiendra les éléments Image et Text de CenterAlignedTopAppBar.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier){
   CenterAlignedTopAppBar(
       title = {
           Row() {

           }
       },
       modifier = modifier
   )
}
  1. Ajoutez le logo Image dans Row.
  • Définissez la taille de l'image dans le modifier en tant que image_size dans le fichier dimens.xml, puis fixez la marge intérieure avec padding_small dans le même fichier dimens.xml.
  • Utilisez painter pour définir Image sur ic_woof_logo à partir du dossier drawable.
  • Définissez contentDescription sur null. Dans ce cas, le logo de l'application n'ajoute aucune information sémantique pour les utilisateurs malvoyants. Il n'est donc pas nécessaire d'ajouter une description du contenu.
Row() {
   Image(
       modifier = Modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small)),
       painter = painterResource(R.drawable.ic_woof_logo),
       contentDescription = null
   )
}
  1. Ajoutez ensuite un composable Text dans Row après l'élément Image..
  • Utilisez stringResource() pour le définir sur la valeur de app_name. Le texte prendra alors le nom de l'application, stocké dans strings.xml.
  • Définissez le style du texte sur displayLarge, car le nom de l'application est une information courte et importante.
Text(
   text = stringResource(R.string.app_name),
   style = MaterialTheme.typography.displayLarge
)

Aperçu de l'application Woof avec la barre d'application supérieure

Voici ce qui s'affiche dans WoofPreview(). L'apparence n'est pas parfaite, car l'icône et le texte ne sont pas alignés verticalement.

  1. Pour résoudre ce problème, ajoutez un paramètre de valeur verticalAlignment à Row et définissez-le sur Alignment.CenterVertically.
import androidx.compose.ui.Alignment

Row(
   verticalAlignment = Alignment.CenterVertically
)

Aperçu de l'application Woof avec la barre d'application supérieure centrée verticalement

C'est beaucoup mieux !

Voici le composable WoofTopAppBar() complet :

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       title = {
           Row(
               verticalAlignment = Alignment.CenterVertically
           ) {
               Image(
                   modifier = Modifier
                       .size(dimensionResource(id = R.dimen.image_size))
                       .padding(dimensionResource(id = R.dimen.padding_small)),
                   painter = painterResource(R.drawable.ic_woof_logo),

                   contentDescription = null
               )
               Text(
                   text = stringResource(R.string.app_name),
                   style = MaterialTheme.typography.displayLarge
               )
           }
       },
       modifier = modifier
   )
}

Exécutez l'application et admirez la façon dont la TopAppBar se fond élégamment avec le reste.

Sans barre d'application supérieure

Avec la barre d'application supérieure

Et maintenant, observez la version finale de l'application avec le thème sombre !

2776e6a45cf3434a.png

Félicitations, vous avez terminé cet atelier de programmation !

8. Télécharger le code de solution

Pour télécharger le code de cet atelier de programmation terminé, utilisez les commandes Git suivantes :

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout material

Vous pouvez également télécharger le dépôt sous forme de fichier ZIP, le décompresser et l'ouvrir dans Android Studio.

Si vous souhaitez voir le code de solution, affichez-le sur GitHub.

9. Conclusion

Vous venez de créer votre première application Material. Vous avez créé une palette de couleurs personnalisée pour le thème clair et le thème sombre, créé des formes pour différents composants, téléchargé des polices et ajouté ces éléments à l'application, puis créé une belle barre supérieure pour unifier le tout. Mettez à profit les compétences acquises dans cet atelier de programmation pour modifier les couleurs, les formes et la typographie afin d'apporter une touche personnelle à vos applications !

Résumé

  • La thématisation Material vous permet d'utiliser Material Design dans votre application et vous offre des conseils pour personnaliser ses couleurs, sa typographie et ses formes.
  • Le thème est défini dans le fichier Theme.kt via un composable appelé [your app name]+Theme() (WoofTheme()), dans le cas de cette appli. Dans cette fonction, l'objet MaterialTheme définit les paramètres color, typography, shapes et content.
  • Color.kt vous permet de définir la liste des couleurs que vous utilisez dans l'application. Ensuite, dans Theme.kt, vous attribuez les couleurs dans LightColorPalette et DarkColorPalette à des emplacements spécifiques. Il n'est pas nécessaire d'attribuer tous les emplacements.
  • Vous pouvez activer Forcer le mode sombre dans votre application pour que le système applique un thème sombre. Si vous forcez le thème sombre, vos utilisateurs bénéficient d'une meilleure expérience, ce qui vous permet de garder le contrôle du thème de l'application.
  • Shape.kt vous permet de définir les formes de votre application. Il existe trois tailles possibles : petite, moyenne et grande. Vous pouvez régler l'arrondi des angles.
  • Les formes permettent de capter l'attention, d'identifier les composants, de communiquer un état et d'exprimer une image de marque.
  • Dans le fichier Type.kt, vous initialisez vos polices et attribuez les propriétés fontFamily, fontWeight et fontSize pour l'échelle de type Material Design.
  • L'échelle de type Material Design comprend une gamme de styles contrastés qui répondent aux besoins de votre application et de son contenu. L'échelle de type combine 15 styles compatibles avec le système de types.

10. En savoir plus