Limiter l'orientation de l'application 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 ?

Ce guide est une mesure temporaire jusqu'à ce que votre application soit entièrement compatible avec toutes les configurations d'appareils.

Gérer l'orientation de l'application

Pour activer l'orientation paysage sur les grands écrans, définissez le fichier manifeste de votre application pour qu'il gère les changements d'orientation par défaut. 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 plus précisément au comportement défini par l'utilisateur pour l'appareil: si l'utilisateur a verrouillé la rotation basée sur le capteur, l'application suit ses préférences ; sinon, le système autorise l'une des quatre orientations d'écran possibles (portrait, paysage, portrait inversé ou paysage inversé). Voir 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 WindowMetricsCalculator#computeMaximumWindowMetrics() de Jetpack WindowManager 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 de fenêtre 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 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 de computeMaximumWindowMetrics().
  • La méthode computeMaximumWindowMetrics() est utilisée à la place de computeCurrentWindowMetrics(), 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.

Points essentiels

  • 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 vous permettant de déterminer la taille et le format de la fenêtre de l'application, rétrocompatible avec le niveau d'API 14.
  • Activity#setRequestedOrientation(): méthode vous permettant de modifier l'orientation de l'application au moment de l'exécution.

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 doit être compatible avec les orientations paysage et portrait.

Collections contenant ce guide

Ce guide fait partie de ces collections de guides rapides sélectionnés qui couvrent des objectifs de développement Android plus larges:

Assurez-vous que votre application propose une expérience utilisateur optimisée sur les tablettes, les appareils pliables et les appareils ChromeOS.

Vous avez des questions ou des commentaires ?

Consultez notre page des questions fréquentes et découvrez les guides rapides, ou contactez-nous pour nous faire part de vos commentaires.