Android vous fournit tous les ingrédients dont vous avez besoin pour "concocter" des applications grand écran 5 étoiles. Les recettes de ce livre sélectionnent et combinent des ingrédients de choix pour résoudre des problèmes de développement spécifiques. Chaque recette inclut des bonnes pratiques, des exemples de code de qualité et des instructions détaillées pour vous aider à devenir un "top chef" des applications grand écran.
Notes de 1 à 5 étoiles
Les recettes sont évaluées en fonction de leur niveau d'adéquation avec les consignes relatives à la qualité des applis sur les grands écrans.
Répond aux critères du niveau 1 (différencié pour les grands écrans) | |
Répond aux critères du niveau 2 (optimisé pour les grands écrans) | |
Répond aux critères de niveau 3 (adapté aux grands écrans) | |
Propose des fonctionnalités sur grand écran, mais ne respecte pas les consignes relatives à la qualité des applications sur grand écran | |
Répond aux besoins d'un cas d'utilisation spécifique, mais n'est pas adapté aux grands écrans |
Prise en charge de l'appareil photo Chromebook
Faites-vous remarquer sur Google Play par les utilisateurs de Chromebook.
Si votre application peut être utilisée avec des fonctionnalités de caméra/appareil photo de base seulement, ne laissez pas les plates-formes de téléchargement d'applications empêcher les utilisateurs de Chromebooks d'installer l'application juste parce que vous avez accidentellement spécifié des fonctionnalités avancées de caméra/appareil photo que l'on trouve sur les téléphones haut de gamme.
Les Chromebooks sont dotés d'une caméra frontale intégrée (orientée vers l'utilisateur) qui convient aux visioconférences, aux instantanés et à d'autres usages. Toutefois, tous les Chromebooks ne sont pas équipés d'une caméra arrière, orientée vers l'extérieur. De plus, la plupart des caméras frontales sur les Chromebooks ne sont pas compatibles avec la mise au point automatique ou le flash.
Bonnes pratiques
Les applications de caméra/appareil photo polyvalentes sont compatibles avec tous les appareils, quelle que soit leur configuration : appareils avec caméra frontale, caméra arrière, caméra externe connectée par USB.
Pour vous assurer que les plates-formes de téléchargement d'applications proposent votre application sur le plus grand nombre d'appareils possible, déclarez toujours toutes les fonctionnalités de caméra/appareil photo utilisées par votre application et indiquez explicitement si elles sont requises.
Ingrédients
- Autorisation
CAMERA
: autorise votre application à accéder aux caméras d'un appareil. - Élément
<uses-feature>
du fichier manifeste : informe les plates-formes de téléchargement d'applications des fonctionnalités utilisées par votre application. - Attribut
required
: indique aux plates-formes de téléchargement d'applications si votre application peut fonctionner sans fonctionnalité spécifique.
Étapes
Résumé
Déclarez l'autorisation CAMERA
. Déclarez les fonctionnalités de caméra/appareil photo qui fournissent une compatibilité de base. Indiquez si chaque fonctionnalité est obligatoire ou non.
1. Déclarer l'autorisation CAMERA
Ajoutez l'autorisation suivante au fichier manifeste de l'application :
<uses-permission android:name="android.permission.CAMERA" />
2. Déclarer les fonctionnalités de base de la caméra ou de l'appareil photo
Ajoutez les fonctionnalités suivantes au fichier manifeste de l'application :
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
3. Indiquer si chaque fonctionnalité est obligatoire
Définissez android:required="false"
pour la fonctionnalité android.hardware.camera.any
afin d'autoriser l'accès à votre application sur les appareils qui intègrent une caméra externe ou intégrée, voire aucune caméra.
Pour les autres fonctionnalités, configurez android:required="false"
afin que les appareils tels que les Chromebooks sans caméra arrière, sans mise au point automatique ou sans Flash puissent accéder à votre application sur les plates-formes de téléchargement.
Résultats
Les utilisateurs de Chromebooks peuvent télécharger et installer votre application depuis Google Play et d'autres plates-formes de téléchargement d'applications. De plus, les appareils qui offrent une prise en charge complète, comme les téléphones, pourront exploiter toutes les fonctionnalités de caméra/appareil photo.
Maintenant que vous avez défini explicitement les fonctionnalités de caméra/appareil photo compatibles avec votre application et spécifié celles qu'elle requiert, votre application est accessible à un maximum d'appareils.
Ressources supplémentaires
Pour en savoir plus, consultez la section sur les fonctionnalités matérielles liées à l'appareil photo dans la documentation <uses-feature>
.
Orientation de l'application limitée sur les téléphones, mais pas sur les appareils à grand écran
Votre application fonctionne parfaitement sur les téléphones en mode portrait. Vous avez donc limité l'application à ce mode. Toutefois, vous savez que le mode paysage permettrait d'en faire plus sur les grands écrans.
Comment limiter l'orientation portrait de l'application aux petits écrans, tout en permettant le mode paysage sur les grands écrans ?
Bonnes pratiques
Les meilleures applications respectent les préférences utilisateur telles que l'orientation de l'appareil.
Les consignes relatives à la qualité des applis sur les grands écrans recommandent que les applications soient compatibles avec toutes les configurations d'appareil, y compris les orientations portrait et paysage, le mode multifenêtre ou l'état plié et déplié des appareils pliables. Les applications doivent optimiser les mises en page et les interfaces utilisateur en fonction des différentes configurations. Elles doivent aussi enregistrer et restaurer l'état lors des changements de configuration.
La recette qui suit est une mesure temporaire : elle offre un zeste de compatibilité avec les grands écrans. Utilisez cette recette jusqu'à ce que votre application soit entièrement compatible avec toutes les configurations d'appareils.
Ingrédients
screenOrientation
: paramètre de fichier manifeste d'application qui vous permet de spécifier la manière dont votre application réagit aux changements d'orientation de l'appareil.- Jetpack WindowManager: ensemble de bibliothèques permettant de déterminer la taille et le format de la fenêtre de l'application rétrocompatible jusqu'au niveau d'API 14
Activity#setRequestedOrientation()
: méthode vous permettant de modifier l'orientation de l'application au moment de l'exécution.
Étapes
Résumé
Autorisez l'application à gérer les changements d'orientation par défaut dans son fichier manifeste. Au moment de l'exécution, déterminez la taille de la fenêtre de l'application. Si elle est petite, limitez l'orientation de l'application en remplaçant le paramètre d'orientation du fichier manifeste.
1. Spécifier le paramètre d'orientation dans le fichier manifeste de l'application
Vous pouvez éviter de déclarer l'élément screenOrientation
du fichier manifeste d'application (dans ce cas, l'orientation par défaut est unspecified
) ou définir l'orientation de l'écran sur fullUser
. Si l'utilisateur n'a pas verrouillé la rotation basée sur le capteur, votre application accepte toutes les orientations d'appareil.
<activity
android:name=".MyActivity"
android:screenOrientation="fullUser">
La différence entre unspecified
et fullUser
est subtile, mais importante. Si vous ne déclarez pas de valeur screenOrientation
, le système choisit l'orientation. La règle utilisée pour définir l'orientation peut varier d'un appareil à l'autre. En revanche, spécifier fullUser
correspond mieux au comportement que l'utilisateur a défini pour l'appareil : si l'utilisateur a verrouillé la rotation basée sur le capteur, l'application suit ses préférences. Dans le cas contraire, le système autorise l'une des quatre orientations d'écran possibles (portrait, paysage, portrait inversé ou paysage inversé). Voir android:screenOrientation
.
2. Déterminer la taille de l'écran
Comme le fichier manifeste permet toutes les orientations autorisées par l'utilisateur, vous pouvez spécifier l'orientation de l'application par programmation en fonction de la taille de l'écran.
Ajoutez les bibliothèques Jetpack WindowManager au fichier build.gradle
ou build.gradle.kts
du module:
Kotlin
implementation("androidx.window:window:version
") implementation("androidx.window:window-core:version
")
Groovy
implementation 'androidx.window:window:version
' implementation 'androidx.window:window-core:version
'
Utilisez la méthode Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics()
pour obtenir la taille d'écran de l'appareil en tant qu'objet WindowMetrics
. Les métriques de fenêtre peuvent être comparées aux classes de taille de fenêtre pour décider quand limiter l'orientation.
Les classes de taille Windows fournissent des points d'arrêt entre les petits et les grands écrans.
Utilisez les points d'arrêt WindowWidthSizeClass#COMPACT
et WindowHeightSizeClass#COMPACT
pour déterminer la taille de l'écran :
Kotlin
/** Determines whether the device has a compact screen. **/ fun compactScreen() : Boolean { val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT }
Java
/** Determines whether the device has a compact screen. **/ private boolean compactScreen() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this); int width = metrics.getBounds().width(); int height = metrics.getBounds().height(); float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density); return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT || windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT; }
- Remarque :
- Les exemples ci-dessus sont implémentés en tant que méthodes d'une activité. Dès lors, l'activité est "déréférencée" avec l'attribut
this
dans l'argument decomputeMaximumWindowMetrics()
. - La méthode
computeMaximumWindowMetrics()
est utilisée à la place decomputeCurrentWindowMetrics()
, car l'application peut être lancée en mode multifenêtre, ce qui ignore le paramètre d'orientation de l'écran. Il est inutile de déterminer la taille de la fenêtre de l'application et de remplacer le paramètre d'orientation, sauf si la fenêtre de l'application correspond à la totalité de l'écran de l'appareil.
Consultez la section WindowManager pour découvrir comment déclarer des dépendances afin de rendre la méthode computeMaximumWindowMetrics()
disponible dans votre application.
3. Remplacer le paramètre du fichier manifeste d'application
Une fois que vous avez déterminé que l'appareil est doté d'une taille d'écran compacte, vous pouvez appeler Activity#setRequestedOrientation()
pour remplacer le paramètre screenOrientation
du fichier manifeste :
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER } }) }
Java
@Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstanceState); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } } }); }
En ajoutant la logique aux méthodes onCreate()
et View.onConfigurationChanged()
, vous pouvez obtenir les métriques de fenêtre maximales et remplacer le paramètre d'orientation chaque fois que l'activité est redimensionnée ou déplacée entre les écrans, par exemple après une rotation de l'appareil ou lorsqu'un appareil pliable est plié ou déplié.
Pour savoir quand des modifications de configuration se produisent et à quel moment elles provoquent la recréation d'une activité, consultez la section Gérer les modifications de configuration.
Résultats
Votre application devrait désormais rester en mode portrait sur les petits écrans, quelle que soit la rotation de l'appareil. Sur les grands écrans, elle devrait être compatible avec les orientations paysage et portrait.
Ressources supplémentaires
Pour découvrir comment mettre à niveau de votre application afin qu'elle soit toujours compatible avec toutes les configurations d'appareil, consultez les ressources suivantes :
- Assurer la compatibilité avec différentes tailles d'écran
- Gérer les modifications de configuration
- Enregistrer les états de l'interface utilisateur
Pause et reprise de la lecture de contenus multimédias avec la barre d'espace du clavier externe
L'optimisation pour les grands écrans doit permettre les interactions au moyen d'un clavier externe, par exemple lorsque l'utilisateur appuie sur la barre d'espace pour mettre en pause ou reprendre la lecture de vidéos et d'autres contenus multimédias. Cela est particulièrement utile pour les tablettes, qui sont souvent connectées à des claviers externes, et pour les Chromebooks, qui sont généralement équipés de claviers externes, mais qui peuvent être utilisés en mode Tablette.
Lorsque le contenu multimédia est le seul élément de la fenêtre (par exemple, durant la lecture d'une vidéo en plein écran), répondez aux événements de pression sur une touche au niveau de l'activité ou, dans Jetpack Compose, au niveau de l'écran.
Bonnes pratiques
Chaque fois que votre application lit un fichier multimédia, les utilisateurs doivent pouvoir suspendre et reprendre la lecture en appuyant sur la barre d'espace d'un clavier physique.
Ingrédients
KEYCODE_SPACE
: constante de code de touche pour la barre d'espace.
Compose
onPreviewKeyEvent
:Modifier
qui permet à un composant d'intercepter les événements de touche matérielle lorsque celui-ci (ou l'un de ses enfants) est sélectionné.onKeyEvent
: à l'instar deonPreviewKeyEvent
, ceModifier
permet à un composant d'intercepter les événements de touche matérielle lorsque celui-ci (ou l'un de ses enfants) est sélectionné.
Vues
onKeyUp()
: appelé lorsqu'une touche est relâchée et qu'elle n'est pas gérée par une vue dans une activité.
Étapes
Résumé
Les applications basées sur les vues et basées sur Jetpack Compose réagissent aux pressions sur les touches du clavier de la même manière : l'application doit écouter les événements de pression sur les touches, les filtrer et répondre aux pressions de touches sélectionnées, comme une barre d'espace.
1. Écouter les événements de clavier
Vues
Dans une activité dans votre application, remplacez la méthode onKeyUp()
:
Kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { ... }
Java
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { ... }
Cette méthode est appelée chaque fois qu'une touche est relâchée. Elle se déclenche exactement une fois pour chaque frappe.
Compose
Avec Jetpack Compose, vous pouvez tirer parti du modificateur onPreviewKeyEvent
ou onKeyEvent
au sein de l'écran qui gère la frappe :
Column(modifier = Modifier.onPreviewKeyEvent { event ->
if (event.type == KeyEventType.KeyUp) {
...
}
...
})
ou
Column(modifier = Modifier.onKeyEvent { event ->
if (event.type == KeyEventType.KeyUp) {
...
}
...
})
2. Filtrer les appuis sur la barre d'espace
Dans la méthode onKeyUp()
, ou dans les méthodes des modificateurs onPreviewKeyEvent
et onKeyEvent
Compose, filtrez KeyEvent.KEYCODE_SPACE
pour envoyer l'événement approprié à votre composant multimédia :
Vues
Kotlin
if (keyCode == KeyEvent.KEYCODE_SPACE) { togglePlayback() return true } return false
Java
if (keyCode == KeyEvent.KEYCODE_SPACE) { togglePlayback(); return true; } return false;
Compose
Column(modifier = Modifier.onPreviewKeyEvent { event ->
if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
...
}
...
})
ou
Column(modifier = Modifier.onKeyEvent { event ->
if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
...
}
...
})
Résultats
Votre application peut désormais réagir aux appuis sur la barre d'espace pour mettre en pause et reprendre la lecture d'une vidéo ou d'un autre type de contenu multimédia.
Ressources supplémentaires
Pour en savoir plus sur les événements de clavier et leur gestion, consultez la section Gérer la saisie au clavier.
Refus de la paume de la main avec le stylet
Un stylet peut être un outil incroyablement productif et créatif sur les grands écrans. Toutefois, lorsque les utilisateurs dessinent, écrivent ou interagissent avec une application à l'aide d'un stylet, ils touchent parfois l'écran avec la paume de leur main. L'événement tactile peut être signalé à votre application avant que le système ne le reconnaisse et l'ignore comme une pression involontaire de la paume de la main.
Bonnes pratiques
Votre application doit identifier les événements tactiles involontaires et les ignorer. Android annule une pression de la paume de la main en envoyant un objet MotionEvent
. Vérifiez si l'objet contient ACTION_CANCEL
ou ACTION_POINTER_UP
et FLAG_CANCELED
afin de déterminer s'il faut rejeter le geste causé par la pression de la paume de la main.
Ingrédients
MotionEvent
: représente les événements tactiles et de mouvement. Contient les informations nécessaires pour déterminer si un événement doit être ignoré.OnTouchListener#onTouch()
: reçoit des objetsMotionEvent
.MotionEvent#getActionMasked()
: renvoie l'action associée à un événement de mouvement.ACTION_CANCEL
: constanteMotionEvent
indiquant qu'un geste doit être annulé.ACTION_POINTER_UP
: constanteMotionEvent
indiquant qu'un autre pointeur que le premier a augmenté (c'est-à-dire qu'il a abandonné le contact avec l'écran de l'appareil).FLAG_CANCELED
: constanteMotionEvent
indiquant que le pointeur a provoqué un événement tactile non intentionnel. Ajout aux événementsACTION_POINTER_UP
etACTION_CANCEL
sur Android 13 (niveau d'API 33) ou version ultérieure.
Étapes
Résumé
Examinez les objets MotionEvent
envoyés à votre application. Utilisez les API MotionEvent
pour déterminer les caractéristiques des événements :
- Événements à pointeur unique : recherchez
ACTION_CANCEL
. Sur Android 13 et versions ultérieures, recherchez égalementFLAG_CANCELED
. - Événements à pointeurs multiples : sur Android 13 et versions ultérieures, recherchez
ACTION_POINTER_UP
etFLAG_CANCELED
.
Répondez aux événements ACTION_CANCEL
et ACTION_POINTER_UP
/FLAG_CANCELED
.
1. Acquérir des objets d'événement de mouvement
Ajoutez un OnTouchListener
à votre application :
Kotlin
val myView = findViewById<View>(R.id.myView).apply { setOnTouchListener { view, event -> // Process motion event. } }
Java
View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { // Process motion event. });
2. Déterminer l'action et les indicateurs d'événement
Recherchez ACTION_CANCEL
, qui indique un événement à pointeur unique à tous les niveaux d'API. Sur Android 13 ou version ultérieure, vérifiez ACTION_POINTER_UP
pour FLAG_CANCELED.
.
Kotlin
val myView = findViewById<View>(R.id.myView).apply { setOnTouchListener { view, event -> when (event.actionMasked) { MotionEvent.ACTION_CANCEL -> { //Process canceled single-pointer motion event for all SDK versions. } MotionEvent.ACTION_POINTER_UP -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } } true } }
Java
View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { switch (event.getActionMasked()) { case MotionEvent.ACTION_CANCEL: // Process canceled single-pointer motion event for all SDK versions. case MotionEvent.ACTION_UP: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } return true; });
3. Annuler le geste
Après avoir identifié une pression de la paume de la main, vous pouvez annuler les effets à l'écran du geste.
Votre application doit conserver un historique des actions de l'utilisateur pour que les entrées involontaires (comme les pressions avec la paume de la main) puissent être annulées. Pour voir un exemple, consultez Implémenter une application de dessin de base dans l'atelier de programmation Améliorer la prise en charge des stylets dans une application Android.
Résultats
Votre application peut désormais identifier et refuser les gestes de la paume de la main pour les événements à plusieurs pointeurs sur Android 13 ou version ultérieure, et pour les événements à pointeur unique à tous les niveaux d'API.
Ressources supplémentaires
Pour en savoir plus, consultez les ressources suivantes :
- Fonctionnalités et API d'Android 13 : amélioration du refus de la paume de la main
- Guides du développeur
- Atelier de programmation : Améliorer la prise en charge des stylets dans une application Android
Gestion de l'état WebView
WebView
est un composant couramment utilisé qui propose un système avancé de gestion des états. Un WebView
doit conserver son état et sa position de défilement lors des modifications de configuration. Un WebView
peut perdre la position de défilement lorsque l'utilisateur fait pivoter l'appareil ou déplie un téléphone pliable, ce qui l'oblige à faire défiler à nouveau la WebView
du haut jusqu'à la position de défilement précédente.
Bonnes pratiques
Minimisez le nombre de fois où une WebView
est recréée. WebView
est capable de gérer efficacement son état, et vous pouvez en profiter pour gérer autant de modifications de configuration que possible. Votre application doit gérer les modifications de configuration, car la recréation d'Activity
(méthode du système pour gérer les modifications de configuration) recrée également la WebView
, ce qui entraîne la perte de l'état de la WebView
.
Ingrédients
android:configChanges
: attribut de l'élément<activity>
du fichier manifeste. Recense les modifications de configuration gérées par l'activité.View#invalidate()
: lorsque cette méthode est utilisée, une vue est redessinée. Héritée parWebView
.
Étapes
Résumé
Pour enregistrer l'état de la WebView
, évitez autant que possible la recréation d'Activity
et laissez ensuite la WebView
s'invalider afin qu'elle puisse se redimensionner tout en conservant son état.
1. Ajouter des modifications de configuration au fichier AndroidManifest.xml
de votre application
Pour éviter la recréation de l'activité, spécifiez les modifications de configuration gérées par votre application (plutôt que par le système) :
<activity
android:name=".MyActivity"
android:configChanges="screenLayout|orientation|screenSize
|keyboard|keyboardHidden|smallestScreenSize" />
2. Invalider la WebView
chaque fois que votre application reçoit une modification de configuration
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) webView.invalidate() }
Java
@Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); webview.invalidate(); }
Cette étape ne s'applique qu'au système de vues, car Jetpack Compose n'a pas besoin d'invalider quoi que ce soit pour redimensionner correctement les éléments Composable
. Cependant, Compose recrée souvent un élément WebView
s'il n'est pas géré correctement. Utilisez le wrapper Accompanist WebView pour enregistrer et restaurer l'état de la WebView
dans vos applications Compose.
Résultats
Les composants WebView
de votre application conservent désormais leur état et leur position de défilement lors de plusieurs modifications de configuration, du redimensionnement au changement d'orientation, en passant par le pliage et le dépliage.
Ressources supplémentaires
Pour en savoir plus sur les modifications de configuration et sur leur gestion, consultez la page Gérer les modifications de configuration.
Gestion de l'état RecyclerView
RecyclerView
peut afficher de grandes quantités de données à l'aide de ressources graphiques minimales. Lorsque RecyclerView
fait défiler la liste des éléments, RecyclerView
réutilise les instances View
des éléments qui défilent hors de l'écran pour créer d'autres éléments lorsqu'ils défilent à l'écran. Toutefois, les modifications de configuration telles que la rotation de l'appareil peuvent réinitialiser l'état d'une RecyclerView
, ce qui oblige les utilisateurs à faire défiler l'écran jusqu'à leur position précédente dans la liste des éléments RecyclerView
.
Bonnes pratiques
RecyclerView
doit conserver son état, en particulier sa position de défilement, ainsi que l'état de ses éléments de liste lors de toutes les modifications de configuration.
Ingrédients
RecyclerView.Adapter#setStateRestorationPolicy()
: spécifie comment unRecyclerView.Adapter
restaure son état après un changement de configuration.ViewModel
: conserve l'état d'une activité ou d'un fragment.
Étapes
Résumé
Définissez la stratégie de restauration d'état de RecyclerView.Adapter
pour enregistrer la position de défilement RecyclerView
. Enregistrez l'état des éléments de liste de RecyclerView
. Ajoutez l'état des éléments de liste à l'adaptateur RecyclerView
, puis restaurez l'état des éléments de liste lorsqu'ils sont associés à un ViewHolder
.
1. Activer la stratégie de restauration d'état d'Adapter
Activez la stratégie de restauration d'état de l'adaptateur RecyclerView
afin que la position de défilement de RecyclerView
soit maintenue en cas de modification de la configuration. Ajoutez la spécification de stratégie au constructeur de l'adaptateur :
Kotlin
class MyAdapter() : RecyclerView.Adapter() { init { stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY } ... }
Java
class MyAdapter extends RecyclerView.Adapter{ public Adapter() { setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY); } ... }
2. Enregistrer l'état des éléments de liste avec état
Enregistrez l'état d'éléments de liste RecyclerView
complexes, tels que les éléments contenant des éléments EditText
. Par exemple, pour enregistrer l'état d'un EditText
, ajoutez un rappel semblable à un gestionnaire onClick
afin de capturer les modifications de texte. Dans le rappel, définissez les données à enregistrer :
Kotlin
input.addTextChangedListener( afterTextChanged = { text -> text?.let { // Save state here. } } )
Java
input.addTextChangedListener(new TextWatcher() { ... @Override public void afterTextChanged(Editable s) { // Save state here. } });
Déclarez le rappel dans votre Activity
ou votre Fragment
. Utilisez un ViewModel
pour stocker l'état.
3. Ajouter l'état de l'élément de liste à Adapter
Ajoutez l'état des éléments de liste à votre RecyclerView.Adapter
. Transmettez l'état de l'élément au constructeur de l'adaptateur lors de la création de l'Activity
ou Fragment
hôte :
Kotlin
val adapter = MyAdapter(items, viewModel.retrieveState())
Java
MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());
4. Récupérer l'état de l'élément de liste dans le ViewHolder
de l'adaptateur
Dans RecyclerView.Adapter
, lorsque vous liez un ViewHolder
à un élément, restaurez l'état de l'élément :
Kotlin
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { ... val item = items[position] val state = states.firstOrNull { it.item == item } if (state != null) { holder.restore(state) } }
Java
@Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { ... Item item = items[position]; Arrays.stream(states).filter(state -> state.item == item) .findFirst() .ifPresent(state -> holder.restore(state)); }
Résultats
Votre RecyclerView
peut désormais restaurer sa position de défilement et l'état de chaque élément de la liste RecyclerView
.
Ressources supplémentaires
Gestion du clavier détachable
La prise en charge des claviers détachables permet de maximiser la productivité des utilisateurs sur des
appareils dotés d'un écran. Android déclenche une modification de configuration chaque fois qu'un clavier est
connecté à un appareil ou déconnecté de celui-ci, ce qui peut entraîner une perte de l'état de l'UI. Votre
l'application peut soit enregistrer et restaurer son état, ce qui permet au système de gérer
la recréation d'activités ou la restriction de la recréation d'activités pour les modifications de configuration du clavier.
Dans tous les cas, toutes les données relatives au clavier sont stockées
objet Configuration
. Les keyboard
et
Les champs keyboardHidden
de l'objet de configuration contiennent des informations sur le type
et sa disponibilité.
Bonnes pratiques
Les applications optimisées pour les grands écrans sont compatibles avec tous les types de périphériques d'entrée : claviers logiciels et matériels pour stylets, souris, pavés tactiles et autres périphériques appareils.
La prise en charge des claviers externes implique des modifications de configuration, que vous pouvez gérer de deux manières:
- Laissez le système recréer l'activité en cours d'exécution, et vous vous occupez de la gestion de l'état de votre application.
- Gérez vous-même le changement de configuration (l'activité ne sera pas recréée):
<ph type="x-smartling-placeholder">
- </ph>
- Déclarer toutes les valeurs de configuration associées au clavier
- Créer un gestionnaire de modifications de configuration
Les applications de productivité, qui nécessitent souvent un contrôle précis de l'interface utilisateur pour la saisie de texte et peuvent bénéficier d'une approche personnalisée les modifications de configuration.
Dans certains cas, vous pouvez modifier la mise en page de votre application clavier est installé ou détaché, par exemple, pour laisser plus de place aux outils ou des fenêtres de modification.
Étant donné que le seul moyen fiable d'écouter les modifications de configuration est de remplacer
la méthode onConfigurationChanged()
d'une vue, vous pouvez ajouter une nouvelle vue
à l'activité de votre application et répondre dans le onConfigurationChanged()
de la vue
aux modifications de configuration causées par la connexion du clavier ou
détachée.
Ingrédients
android:configChanges
: attribut de l'élément<activity>
du fichier manifeste de l'application. Informe le système des modifications de configuration gérées par l'application.View#onConfigurationChanged()
: méthode qui réagit à la propagation d'une nouvelle la configuration de l'application.
Étapes
Résumé
Déclarez l'attribut configChanges
et ajoutez des valeurs liées au clavier. Ajoutez un
View
à la hiérarchie des vues de l'activité et écouter les modifications de configuration.
1. Déclarer l'attribut configChanges
Mettez à jour l'élément <activity>
dans le fichier manifeste de l'application en ajoutant les valeurs keyboard|keyboardHidden
à la liste des modifications de configuration déjà gérées:
<activity
…
android:configChanges="...|keyboard|keyboardHidden">
2. Ajouter une vue vide à la hiérarchie des vues
Déclarez une nouvelle vue et ajoutez votre code de gestionnaire dans la méthode onConfigurationChanged()
de la vue:
Kotlin
val v = object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) // Handler code here. } }
Java
View v = new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Handler code here. } };
Résultats
Votre application répondra désormais à l'association ou à la dissociation d'un clavier externe sans recréer l'activité en cours.
Ressources supplémentaires
Pour savoir comment enregistrer l'état de l'interface utilisateur de votre application lors de modifications de configuration telles que l'ajout ou la dissociation d'un clavier, consultez Enregistrer les états de l'interface utilisateur.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Gérer les modifications de configuration