Rotation de la gestion

Cette rubrique explique comment gérer les modifications d’orientation de l’appareil dans Xamarin.Android. Il explique comment utiliser le système de ressources Android pour charger automatiquement des ressources pour une orientation particulière de l’appareil et comment gérer par programme les modifications d’orientation.

Vue d’ensemble

Étant donné que les appareils mobiles sont facilement pivotés, la rotation intégrée est une fonctionnalité standard des systèmes d’exploitation mobiles. Android fournit une infrastructure sophistiquée pour gérer la rotation au sein des applications, que l’interface utilisateur soit créée de manière déclarative en XML ou par programmation dans le code. Lorsque vous gérez automatiquement les modifications de disposition déclaratives sur un appareil pivoté, une application peut bénéficier de l’intégration étroite avec le système de ressources Android. Pour la disposition programmatique, les modifications doivent être gérées manuellement. Cela permet un contrôle plus fin au moment de l’exécution, mais au détriment de plus de travail pour le développeur. Une application peut également choisir de désactiver le redémarrage de l’activité et de prendre un contrôle manuel des modifications d’orientation.

Ce guide examine les rubriques d’orientation suivantes :

  • Rotation déclarative de la disposition : comment utiliser le système de ressources Android pour créer des applications prenant en charge l’orientation, notamment la façon de charger à la fois des dispositions et des dessins pour des orientations particulières.

  • Rotation de disposition programmatique : comment ajouter des contrôles par programmation, ainsi que comment gérer manuellement les modifications d’orientation.

Gestion de la rotation de manière déclarative avec des dispositions

En incluant des fichiers dans des dossiers qui suivent les conventions d’affectation de noms, Android charge automatiquement les fichiers appropriés lorsque l’orientation change. Cela inclut la prise en charge des éléments suivants :

  • Ressources de disposition : spécification des fichiers de disposition gonflés pour chaque orientation.

  • Ressources dessinables : spécification des tiroirs chargés pour chaque orientation.

Ressources de disposition

Par défaut, les fichiers Android XML (AXML) inclus dans le dossier Ressources/disposition sont utilisés pour le rendu des vues pour une activité. Les ressources de ce dossier sont utilisées pour l’orientation portrait et paysage si aucune ressource de disposition supplémentaire n’est fournie spécifiquement pour le paysage. Considérez la structure du projet créée par le modèle de projet par défaut :

Structure du modèle de projet par défaut

Ce projet crée un seul fichier Main.axml dans le dossier Resources/layout . Lorsque la méthode de l’activité OnCreate est appelée, elle gonfle la vue définie dans Main.axml, qui déclare un bouton comme indiqué dans le code XML ci-dessous :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
<Button  
  android:id="@+id/myButton"
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content" 
  android:text="@string/hello"/>
</LinearLayout>

Si l’appareil est pivoté vers l’orientation paysage, la méthode de l’activité OnCreate est appelée à nouveau et le même fichier Main.axml est gonflé, comme illustré dans la capture d’écran ci-dessous :

Même écran, mais en orientation paysage

Dispositions spécifiques à l’orientation

Outre le dossier de disposition (qui est défini par défaut sur portrait et peut également être explicitement nommé layout-port en incluant un dossier nommé layout-land), une application peut définir les vues dont elle a besoin lorsqu’elle est en paysage sans aucune modification du code.

Supposons que le fichier Main.axml contenait le code XML suivant :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView
    android:text="This is portrait"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" />
</RelativeLayout>

Si un dossier nommé layout-land qui contient un fichier Main.axml supplémentaire est ajouté au projet, l’inflation de la disposition lorsque le paysage entraîne désormais le chargement Android du fichier Main.axml nouvellement ajouté. Considérez la version paysage du fichier Main.axml qui contient le code suivant (par souci de simplicité, ce code XML est similaire à la version portrait par défaut du code, mais utilise une chaîne différente dans le TextViewcode) :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView
    android:text="This is landscape"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" />
</RelativeLayout>

L’exécution de ce code et la rotation de l’appareil de portrait en paysage illustre le nouveau chargement XML, comme indiqué ci-dessous :

Captures d’écran portrait et paysage imprimant le mode Portrait

Ressources dessinables

Pendant la rotation, Android traite les ressources dessinables de la même façon que les ressources de disposition. Dans ce cas, le système obtient les tiroirs des dossiers Ressources/dessinables et Ressources/terrains dessinables , respectivement.

Par exemple, supposons que le projet inclut une image nommée Monkey.png dans le dossier Ressources/dessinable, où le dessinable est référencé à partir d’un ImageView fichier XML comme suit :

<ImageView
  android:layout_height="wrap_content"
  android:layout_width="wrap_content"
  android:src="@drawable/monkey"
  android:layout_centerVertical="true"
  android:layout_centerHorizontal="true" />

Supposons également qu’une autre version de Monkey.png est incluse dans les ressources/terrains dessinables. Tout comme avec les fichiers de disposition, lorsque l’appareil est pivoté, les modifications dessinables pour l’orientation donnée, comme indiqué ci-dessous :

Version différente de Monkey.png affichée dans les modes portrait et paysage

Gestion de la rotation par programmation

Parfois, nous définissons des dispositions dans le code. Cela peut se produire pour diverses raisons, notamment les limitations techniques, les préférences des développeurs, etc. Lorsque nous ajoutons des contrôles par programmation, une application doit prendre en compte manuellement l’orientation de l’appareil, qui est gérée automatiquement lorsque nous utilisons des ressources XML.

Ajout de contrôles dans le code

Pour ajouter des contrôles par programmation, une application doit effectuer les étapes suivantes :

  • Créez une disposition.
  • Définissez les paramètres de disposition.
  • Créez des contrôles.
  • Définissez les paramètres de disposition du contrôle.
  • Ajoutez des contrôles à la disposition.
  • Définissez la disposition en tant qu’affichage de contenu.

Par exemple, considérez une interface utilisateur composée d’un seul TextView contrôle ajouté à un RelativeLayout, comme illustré dans le code suivant.

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);
                        
  // create a layout
  var rl = new RelativeLayout (this);

  // set layout parameters
  var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
  rl.LayoutParameters = layoutParams;
        
  // create TextView control
  var tv = new TextView (this);

  // set TextView's LayoutParameters
  tv.LayoutParameters = layoutParams;
  tv.Text = "Programmatic layout";

  // add TextView to the layout
  rl.AddView (tv);
        
  // set the layout as the content view
  SetContentView (rl);
}

Ce code crée une instance d’une RelativeLayout classe et définit sa LayoutParameters propriété. La LayoutParams classe est la façon d’encapsuler la façon dont les contrôles sont positionnés de manière réutilisable. Une fois qu’une instance d’une disposition est créée, les contrôles peuvent être créés et ajoutés à celui-ci. Les contrôles ont LayoutParameterségalement , comme dans TextView cet exemple. Une fois la TextView création terminée, l’ajout de celui-ci à la RelativeLayout RelativeLayout vue de contenu entraîne l’affichage de contenu dans l’application, TextView comme indiqué ci-dessous :

Bouton Incrémenter le compteur affiché dans les modes portrait et paysage

Détection de l’orientation dans le code

Si une application tente de charger une interface utilisateur différente pour chaque orientation lorsqu’elle OnCreate est appelée (cela se produit chaque fois qu’un appareil est pivoté), il doit détecter l’orientation, puis charger le code d’interface utilisateur souhaité. Android a une classe appelée WindowManager, qui peut être utilisée pour déterminer la rotation actuelle de l’appareil via la WindowManager.DefaultDisplay.Rotation propriété, comme indiqué ci-dessous :

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);
                        
  // create a layout
  var rl = new RelativeLayout (this);

  // set layout parameters
  var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
  rl.LayoutParameters = layoutParams;
                        
  // get the initial orientation
  var surfaceOrientation = WindowManager.DefaultDisplay.Rotation;
  // create layout based upon orientation
  RelativeLayout.LayoutParams tvLayoutParams;
                
  if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
    tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
  } else {
    tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
    tvLayoutParams.LeftMargin = 100;
    tvLayoutParams.TopMargin = 100;
  }
                        
  // create TextView control
  var tv = new TextView (this);
  tv.LayoutParameters = tvLayoutParams;
  tv.Text = "Programmatic layout";
        
  // add TextView to the layout
  rl.AddView (tv);
        
  // set the layout as the content view
  SetContentView (rl);
}

Ce code définit la TextView position à positionner 100 pixels à partir du haut à gauche de l’écran, en animant automatiquement la nouvelle disposition, lorsqu’elle est pivotée vers le paysage, comme illustré ici :

L’état d’affichage est conservé dans les modes portrait et paysage

Empêcher le redémarrage de l’activité

Outre la gestion de tout ce qui se trouve, OnCreateune application peut également empêcher le redémarrage d’une activité lorsque l’orientation change en définissant ConfigurationChanges dans les ActivityAttribute étapes suivantes :

[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]

À présent, lorsque l’appareil est pivoté, l’activité n’est pas redémarrée. Pour gérer manuellement le changement d’orientation dans ce cas, une activité peut remplacer la OnConfigurationChanged méthode et déterminer l’orientation de l’objet Configuration passé, comme dans la nouvelle implémentation de l’activité ci-dessous :

[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
public class CodeLayoutActivity : Activity
{
  TextView _tv;
  RelativeLayout.LayoutParams _layoutParamsPortrait;
  RelativeLayout.LayoutParams _layoutParamsLandscape;
                
  protected override void OnCreate (Bundle bundle)
  {
    // create a layout
    // set layout parameters
    // get the initial orientation

    // create portrait and landscape layout for the TextView
    _layoutParamsPortrait = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
                
    _layoutParamsLandscape = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
    _layoutParamsLandscape.LeftMargin = 100;
    _layoutParamsLandscape.TopMargin = 100;
                        
    _tv = new TextView (this);
                        
    if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
      _tv.LayoutParameters = _layoutParamsPortrait;
    } else {
      _tv.LayoutParameters = _layoutParamsLandscape;
    }
                        
    _tv.Text = "Programmatic layout";
    rl.AddView (_tv);
    SetContentView (rl);
  }
                
  public override void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
  {
    base.OnConfigurationChanged (newConfig);
                        
    if (newConfig.Orientation == Android.Content.Res.Orientation.Portrait) {
      _tv.LayoutParameters = _layoutParamsPortrait;
      _tv.Text = "Changed to portrait";
    } else if (newConfig.Orientation == Android.Content.Res.Orientation.Landscape) {
      _tv.LayoutParameters = _layoutParamsLandscape;
      _tv.Text = "Changed to landscape";
    }
  }
}

Ici, les TextView's paramètres de disposition sont initialisés pour le paysage et le portrait. Les variables de classe contiennent les paramètres, ainsi que l’activité TextView elle-même, car l’activité ne sera pas recréé lorsque l’orientation change. Le code utilise toujours l’entrée surfaceOrientartion OnCreate pour définir la disposition initiale pour le TextView. Après cela, OnConfigurationChanged gère toutes les modifications de disposition suivantes.

Lorsque nous exécutons l’application, Android charge les modifications apportées à l’interface utilisateur à mesure que la rotation de l’appareil se produit et ne redémarre pas l’activité.

Prévention du redémarrage de l’activité pour les dispositions déclaratives

Les redémarrages d’activité provoqués par la rotation de l’appareil peuvent également être empêchés si nous définissons la disposition en XML. Par exemple, nous pouvons utiliser cette approche si nous voulons empêcher un redémarrage d’activité (pour des raisons de performances, peut-être) et nous n’avons pas besoin de charger de nouvelles ressources pour différentes orientations.

Pour ce faire, nous suivons la même procédure que celle que nous utilisons avec une disposition programmatique. Il suffit de définir ConfigurationChanges dans le ActivityAttribute, comme nous l’avons CodeLayoutActivity fait précédemment. Tout code qui doit s’exécuter pour la modification d’orientation peut à nouveau être implémenté dans la OnConfigurationChanged méthode.

Maintien de l’état pendant les modifications d’orientation

Que la gestion de la rotation soit déclarative ou programmatique, toutes les applications Android doivent implémenter les mêmes techniques de gestion de l’état lorsque l’orientation de l’appareil change. La gestion de l’état est importante, car le système redémarre une activité en cours d’exécution lorsqu’un appareil Android est pivoté. Android le fait pour faciliter le chargement de ressources alternatives, telles que des dispositions et des dessins conçus spécifiquement pour une orientation particulière. Quand elle redémarre, l’activité perd tout état temporaire qu’elle peut avoir stocké dans des variables de classe locale. Par conséquent, si une activité dépend de l’état, elle doit conserver son état au niveau de l’application. Une application doit gérer l’enregistrement et la restauration de tout état d’application qu’elle souhaite conserver dans les modifications d’orientation.

Pour plus d’informations sur la persistance de l’état dans Android, reportez-vous au guide de cycle de vie des activités.

Résumé

Cet article a abordé comment utiliser les fonctionnalités intégrées d’Android pour fonctionner avec la rotation. Tout d’abord, il a expliqué comment utiliser le système de ressources Android pour créer des applications prenant en charge l’orientation. Il a ensuite présenté comment ajouter des contrôles dans le code, ainsi que comment gérer manuellement les modifications d’orientation.