Adapter votre application aux appareils pliables

Les grands écrans déployés et les positions pliées uniques offrent de nouvelles expériences utilisateur sur les appareils pliables. Pour que votre application devienne pliable dans Jetpack Compose, utilisez la bibliothèque Compose Material 3 Adaptive, qui fournit des API pour les caractéristiques des fenêtres des appareils pliables telles que les plis, les charnières et les positions de l'appareil. Une application pliable peut adapter sa mise en page pour éviter de placer du contenu important dans les zones des plis ou des charnières et les utiliser comme séparateurs naturels.

Comprendre si un appareil est compatible avec des configurations telles que la position sur table ou la position livre peut vous aider à décider si vous devez prendre en charge différentes mises en page ou fournir des fonctionnalités spécifiques.

Informations sur la fenêtre

Dans Jetpack Compose, utilisez la collectFoldingFeaturesAsState() fonction modulable pour observer les informations de pliage de la fenêtre. collectFoldingFeaturesAsState() collecte les caractéristiques de pliage de la fenêtre actuelle à partir de WindowInfoTracker dans un State Compose contenant une liste d'objets FoldingFeature.

Étant donné que collectFoldingFeaturesAsState() renvoie un State Compose, vos composables se recomposent automatiquement chaque fois que l'état ou la posture de pliage de l'appareil change, sans nécessiter de gestion manuelle du cycle de vie ni de collecte de flux :

@Composable
fun FoldAwareScreen() {
    val foldingFeatures by collectFoldingFeaturesAsState()

    // Access folding features for the current window.
    val foldFeature = foldingFeatures.firstOrNull()
    if (foldFeature != null) {
        // Adapt layout based on the fold feature.
    }
}

Caractéristiques des écrans pliables

La liste des FoldingFeature éléments renvoyés par collectFoldingFeaturesAsState() (un sous-type de DisplayFeature) fournit des informations sur les écrans pliables, y compris les propriétés suivantes :

  • state : position pliée de l'appareil (FLAT ou HALF_OPENED).

  • orientation : orientation du pli ou de la charnière (HORIZONTAL ou VERTICAL).

  • occlusionType : indique si le pli ou la charnière masque une partie de l'écran, NONE ou FULL

  • isSeparating: indique si le pli ou la charnière crée deux zones d'affichage logiques (vrai ou faux).

Un appareil pliable HALF_OPENED signale toujours isSeparating comme vrai, car l'écran est divisé en deux zones d'affichage. De plus, isSeparating est toujours vrai sur un appareil à double écran lorsque l'application recouvre les deux écrans.

La propriété FoldingFeature bounds (héritée de DisplayFeature) représente le rectangle de délimitation d'une caractéristique de pliage telle qu'un pli ou une charnière. Les limites peuvent être utilisées pour positionner des éléments à l'écran par rapport à la caractéristique :

@Composable
fun FoldFeatureDemo() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    if (foldFeature != null) {
        val isSeparating = foldFeature.isSeparating
        val occlusionType = foldFeature.occlusionType
        val bounds = foldFeature.bounds
        // Use bounds and properties to position content.
    }
}

Position sur table

À l'aide des informations incluses dans l'objet FoldingFeature, votre application peut prendre en charge des positions telles que la position sur table, dans laquelle le téléphone est posé sur une surface, la charnière est en position horizontale et l'écran pliable est à moitié ouvert.

La position sur table offre aux utilisateurs la possibilité d'utiliser leur téléphone sans le tenir dans les mains. La position sur table est idéale pour regarder des contenus multimédias, prendre des photos et passer des appels vidéo.

Application de lecteur vidéo en position sur table, avec la lecture vidéo sur la partie verticale droite de l'écran et les commandes de lecture sur la partie horizontale inférieure.
Figure 1. Une application de lecteur vidéo en position sur table : vidéo sur la partie verticale de l'écran, commandes de lecture sur la partie horizontale.

Utilisez FoldingFeature.State et FoldingFeature.Orientation à partir de collectFoldingFeaturesAsState() pour déterminer si l'appareil est en position sur table :

@Composable
fun TabletopContent() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    val isTableTopPosture = foldFeature != null &&
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
        foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL

    if (isTableTopPosture) {
        // Tabletop layout: separate content and controls across the fold.
    } else {
        // Standard layout.
    }
}

Vous pouvez également déterminer si la fenêtre est en position sur table en vérifiant la Posture propriété renvoyée par currentWindowAdaptiveInfoV2() :

val adaptiveInfo = currentWindowAdaptiveInfoV2()
val isTabletop = adaptiveInfo.windowPosture.isTabletop

Une fois que vous savez que l'appareil est en position sur table, mettez à jour la mise en page de votre application en conséquence. Pour les applications multimédias, cela implique généralement de placer la lecture au-dessus du pli, et de placer des commandes de positionnement et du contenu supplémentaire juste en dessous pour une expérience de visionnage ou d'écoute en mode mains libres.

Exemples

Position livre

Le mode Livre est une autre position unique de l'appareil pliable, où l'appareil est à moitié ouvert et la charnière est à la verticale. Le mode Livre est idéal pour lire des e-books. Avec un affichage sur deux pages sur un appareil pliable à grand écran ouvert comme un livre relié, le mode Livre capture l'expérience de lecture d'un vrai livre.

Vous pouvez également l'utiliser pour prendre des photos si vous souhaitez obtenir un autre format tout en gardant les mains libres.

Implémentez le mode Livre avec les mêmes techniques que celles utilisées pour le mode sur table. Vérifiez que l'appareil est plié à la verticale et non à l'horizontale :

@Composable
fun BookContent() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    val isBookPosture = foldFeature != null &&
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
        foldFeature.orientation == FoldingFeature.Orientation.VERTICAL

    if (isBookPosture) {
        // Book posture layout: two-page layout across the vertical fold.
    } else {
        // Standard single-page layout.
    }
}

Changements de taille de la fenêtre

La zone d'affichage d'une application peut changer en raison d'une modification de la configuration de l'appareil, par exemple lorsque l'appareil est plié ou déployé, qu'il pivote ou lorsqu'il est redimensionné en mode multifenêtre.

Pour récupérer la classe de taille de fenêtre actuelle et s'adapter aux changements de taille dans Jetpack Compose, utilisez la fonction composable currentWindowAdaptiveInfoV2() de la bibliothèque Compose Material 3 Adaptive. currentWindowAdaptiveInfoV2() renvoie une instance WindowAdaptiveInfo qui fournit la WindowSizeClass de la fenêtre actuelle (avec la prise en charge des points d'arrêt grands et très grands par défaut), ainsi que la de l'appareilwindowPosture:

@Composable
fun AdaptiveApp() {
    val adaptiveInfo = currentWindowAdaptiveInfoV2()
    val windowSizeClass = adaptiveInfo.windowSizeClass

    when {
        windowSizeClass.isWidthAtLeastBreakpoint(
            WIDTH_DP_EXPANDED_LOWER_BOUND
        ) -> {
            // Expanded layout
        }
        windowSizeClass.isWidthAtLeastBreakpoint(
            WIDTH_DP_MEDIUM_LOWER_BOUND
        ) -> {
            // Medium layout
        }
        else -> {
            // Compact layout
        }
    }
}

Consultez Utiliser des classes de taille de fenêtre.

Ressources supplémentaires

Pour en savoir plus sur les mises en page adaptées au pliage et les appareils pliables, consultez les ressources suivantes :

Exemples

  • Exemple Jetpack WindowManager : exemple d'utilisation de la bibliothèque Jetpack WindowManager
  • Jetcaster : Intégration d'une position à plat avec Compose

Ateliers de programmation