Assurer la compatibilité avec différentes tailles d'écran

La compatibilité avec différentes tailles d'écran permet d'accéder à votre appli le plus largement possible. une variété d'appareils et le plus grand nombre d'utilisateurs.

Pour prendre en charge un maximum de tailles d'écran, concevez vos mises en page d'application pour qu'elles soient réactifs et adaptatifs. Les mises en page responsives et adaptatives permettent d'optimiser l'expérience quelle que soit la taille de l'écran, ce qui permet à votre application de s'adapter aux téléphones, tablettes, appareils pliables, appareils ChromeOS, orientations portrait et paysage, et les configurations redimensionnables, comme le mode multifenêtre, mode.

Les mises en page responsives et adaptatives changent en fonction de l'espace d'affichage disponible. Modifications de petits ajustements de mise en page qui remplissent l'espace (design réactif) à en remplaçant complètement une mise en page par une autre afin que votre application s'adapte au mieux différentes tailles d'écran (design adaptatif).

En tant que kit d'interface utilisateur déclaratif, Jetpack Compose est idéal pour concevoir et Implémentez des mises en page qui changent de manière dynamique pour afficher le contenu différemment sur des écrans de différentes tailles.

Rendre explicites les changements de mise en page importants pour les composables au niveau de l'écran

Lorsque vous utilisez Compose pour mettre en page une application entière, les composables au niveau de l'application et de l'écran occupent tout l'espace qui est alloué à cette application pour afficher l'interface. À ce niveau de la conception, il peut être judicieux de modifier la mise en page globale d'un écran afin d'exploiter les grands écrans.

Évitez d'utiliser des valeurs physiques et matérielles pour prendre des décisions concernant la mise en page. Il pourrait être tentés de prendre des décisions basées sur une valeur tangible fixe (l'appareil est-il tablette ? L'écran physique a-t-il un certain format ?), mais les réponses à ces questions peuvent ne pas être utiles pour déterminer l'espace de fonctionnement de votre UI .

Schéma illustrant différents facteurs de forme d'appareils, y compris téléphone, pliable, tablette et ordinateur portable.
Figure 1 : Facteurs de forme pour téléphone, appareil pliable, tablette et ordinateur portable

Sur les tablettes, il est possible qu'une application s'exécute en mode multifenêtre, ce qui signifie qu'elle peut partager l'écran avec une autre application. Sous ChromeOS, une application peut se trouver dans un une fenêtre redimensionnable. Il peut même y avoir plusieurs écrans physiques, par exemple avec les pliables. Dans tous ces cas, la taille de l'écran physique n'est pas utiles pour décider comment afficher le contenu.

Vous devez plutôt prendre des décisions basées sur la partie de l'écran qui est réellement allouée à votre application, telles que les métriques de fenêtre actuelles fournies par la bibliothèque WindowManager de Jetpack. Pour découvrir comment utiliser WindowManager dans une application Compose, consultez l'exemple JetNews.

Cette approche permet à votre application d'être plus flexible, car son comportement sera approprié dans tous les scénarios ci-dessus. Adapter vos mises en page à l'espace disponible à l'écran permet aussi de réduire le temps de traitement spécial sur des plates-formes comme ChromeOS et sur des facteurs de forme comme les tablettes et les pliables.

Une fois que vous identifiez l'espace approprié disponible pour votre application, il est utile pour convertir la taille brute en une classe de taille significative, comme décrit dans la section Fenêtre classes de taille. Ce regroupe les tailles dans des buckets de taille standard, qui sont des points d'arrêt conçus pour trouver le juste équilibre entre simplicité et flexibilité, afin d'optimiser votre application cas d'utilisation. Ces classes de taille font référence à la fenêtre globale de votre application. Utilisez ces classes pour les décisions de mise en page qui affectent la mise en page globale de votre écran. Vous pouvez transmettre ces classes de taille en tant qu'état, ou exécuter une logique supplémentaire créer un état dérivé à transmettre aux composables imbriqués.

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
    // Perform logic on the size class to decide whether to show the top app bar.
    val showTopAppBar = windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT

    // MyScreen knows nothing about window sizes, and performs logic based on a Boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

Cette approche en couches limite la logique de taille d'écran à un seul emplacement, au lieu de les répartir dans votre application à de nombreux endroits qui doivent rester synchronisés. Cet emplacement unique produit un état, qui peut être explicitement transmis à à d'autres composables, comme vous le feriez pour n'importe quel autre état d'application. La transmission explicite de l'état simplifie les composables individuels, car ils sont simplement traités comme des fonctions modulables standards qui utilisent la classe de taille ou la configuration spécifiée, ainsi que d'autres données.

Les composables imbriqués flexibles sont réutilisables

Les composables qui peuvent être placés à divers endroits sont plus facilement réutilisables. Si un composable suppose qu'il sera toujours placé dans une certaine emplacement avec une taille spécifique, il est alors plus difficile de le réutiliser ailleurs dans une d’un emplacement différent ou avec une quantité d’espace disponible différente. De plus, signifie que les composables individuels et réutilisables doivent éviter de dépendre implicitement sur "global" les informations de taille.

Prenons l'exemple suivant: imaginez un composable imbriqué qui implémente une Liste/Détails mise en page, qui peut afficher un ou deux volets côte à côte.

Capture d'écran d'une application affichant deux volets côte à côte.
Figure 2 : Capture d'écran d'une application affichant une mise en page de vue détaillée en liste : 1 correspond à la zone de liste. 2, la zone de détail.

Cette décision doit faire partie de la mise en page globale de l'application. C'est pourquoi elle est transmise à partir d'un composable au niveau de l'écran, comme nous l'avons vu plus haut :

@Composable
fun AdaptivePane(
    showOnePane: Boolean,
    /* ... */
) {
    if (showOnePane) {
        OnePane(/* ... */)
    } else {
        TwoPane(/* ... */)
    }
}

Et si nous voulons qu'un composable change indépendamment sa mise en page en fonction l'espace disponible ? Par exemple, une carte qui souhaite afficher des informations supplémentaires si l'espace le permet. Nous voulons exécuter une logique basée sur une taille disponible, mais à quelle taille ?

Exemples de deux fiches différentes.
Figure 3 : Fiche étroite affichant uniquement une icône et un titre, et carte plus large affichant l'icône, le titre et une brève description.

Comme nous l'avons vu plus haut, il faut éviter d'essayer d'utiliser la taille réelle de l'appareil l'écran. Cette valeur ne sera ni précise, ni pour plusieurs écrans si l'application n'est pas en plein écran.

Comme le composable n'est pas un composable au niveau de l'écran, les métriques de la fenêtre actuelles ne peuvent pas non plus être utilisées afin de maximiser la réutilisation. Si le composant est placé avec une marge intérieure (par exemple, pour des encarts) ou s'il existe des composants tels que des rails de navigation ou des barres d'application, l'espace disponible pour le composable peut différer considérablement de l'espace global disponible pour l'application.

Par conséquent, nous devons tenir compte de la largeur donnée au composable pour qu'il s'affiche. Deux options s'offrent à nous pour obtenir cette largeur :

Si vous souhaitez modifier l'emplacement ou le mode d'affichage du contenu, vous pouvez utiliser un un ensemble de modificateurs ou une mise en page personnalisée ; pour rendre la mise en page responsive. Vous pouvez par exemple demander à un enfant de remplir tout l'espace disponible ou disposer plusieurs éléments enfants avec plusieurs colonnes s'il y a assez d'espace.

Si vous souhaitez modifier ce qui s'affiche, vous pouvez utiliser BoxWithConstraints comme alternative plus puissante. Ce composable fournit des mesures de contraintes que vous pouvez utiliser pour appeler différents composables en fonction de l'espace disponibles. Cependant, cela entraîne des frais, car BoxWithConstraints reporte la composition jusqu'à la phase de mise en page, lorsque ces contraintes sont connues, ce qui entraîne plus de travail à effectuer pendant la mise en page.

@Composable
fun Card(/* ... */) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(/* ... */)
                Title(/* ... */)
            }
        } else {
            Row {
                Column {
                    Title(/* ... */)
                    Description(/* ... */)
                }
                Image(/* ... */)
            }
        }
    }
}

S'assurer que toutes les données sont compatibles avec différentes tailles

Lorsque vous exploitez l'espace supplémentaire disponible à l'écran, vous pouvez avoir l'espace nécessaire pour présenter plus de contenu à l'utilisateur sur un grand écran que sur un petit écran. Lorsque vous implémentez un composable avec ce comportement, il peut être tentant d'en profiter pour charger les données en tant qu'effet secondaire de la taille actuelle.

Cependant, cela va à l'encontre des principes du flux de données unidirectionnel, où les données peuvent être hissées et fournies aux composables pour s'afficher correctement. Suffisant les données doivent être fournies au composable, de sorte que celui-ci dispose toujours elle doit s'afficher sur n'importe quelle taille, même si une partie des données toujours être utilisées.

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(description)
                }
                Image(imageUrl)
            }
        }
    }
}

En nous appuyant sur l'exemple de fiche (Card), notez que nous transmettons toujours la description à Card. Même si la description n'est utilisée que lorsque la largeur permet de l'afficher, Card l'exige toujours, quelle que soit la largeur disponible.

Le fait de transmettre toujours des données simplifie les mises en page adaptatives en les rendant moins avec état. et cela évite de déclencher des effets secondaires lors du passage d'une taille à une autre (qui peut se produire en raison du redimensionnement d'une fenêtre, d'un changement d'orientation ou du pliage et du dépliage d'un appareil).

Ce principe permet également de préserver l'état entre des modifications de mise en page. Par hissage des informations susceptibles de ne pas être utilisées, nous pouvons conserver l'état à mesure que la taille de la mise en page change. Par exemple, nous pouvons hisser un indicateur booléen showMore. afin que l'état de l'utilisateur soit préservé lorsque les redimensionnements entraînent le passage de la mise en page entre le masquage et l'affichage de la description:

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    var showMore by remember { mutableStateOf(false) }

    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(
                        description = description,
                        showMore = showMore,
                        onShowMoreToggled = { newValue ->
                            showMore = newValue
                        }
                    )
                }
                Image(imageUrl)
            }
        }
    }
}

En savoir plus

Pour en savoir plus sur les mises en page personnalisées dans Compose, consultez les ressources supplémentaires suivantes.

Applications exemples

  • Mises en page standards sur grand écran est un dépôt de modèles de conception éprouvés qui offre une expérience utilisateur optimale sur les appareils à grand écran
  • JetNews montre comment concevoir une application qui adapte son UI pour utiliser l'espace disponible
  • Répondre est un échantillon adaptatif compatible avec les appareils mobiles, les tablettes et les pliables.
  • Now in Android est Application qui utilise les mises en page adaptatives pour prendre en charge différentes tailles d'écran

Vidéos