Ограничить ориентацию приложения на телефонах, но не на устройствах с большим экраном,Ограничить ориентацию приложения на телефонах, но не на устройствах с большим экраном

Ваше приложение отлично работает на телефонах в портретной ориентации, поэтому вы ограничили его только портретной ориентацией. Но вы видите возможность расширить возможности на больших экранах в альбомной ориентации.

Как можно совместить два варианта — ограничить работу приложения в портретной ориентации на маленьких экранах и включить альбомную ориентацию на больших?

Это руководство является временной мерой, пока вы не улучшите свое приложение, обеспечив полную поддержку всех конфигураций устройств.

Результаты

Ваше приложение сохраняет портретную ориентацию на маленьких экранах независимо от поворота устройства. На больших экранах приложение поддерживает альбомную и портретную ориентацию.

Управление ориентацией приложения

Чтобы включить альбомную ориентацию на больших экранах, настройте манифест приложения на обработку изменений ориентации по умолчанию. Определите размер окна приложения во время выполнения. Если окно приложения небольшое, ограничьте ориентацию приложения, переопределив настройку ориентации в манифесте.

1. Укажите настройки ориентации в манифесте приложения.

Вы можете либо не объявлять элемент screenOrientation в манифесте приложения (в этом случае ориентация по умолчанию будет unspecified ), либо установить ориентацию экрана fullUser . Если пользователь не заблокировал поворот экрана с помощью датчиков, ваше приложение будет поддерживать все ориентации устройства.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

Разница между unspecified и fullUser невелика, но важна. Если значение screenOrientation не указано, система выбирает ориентацию, и политика, используемая системой для определения ориентации, может различаться на разных устройствах. С другой стороны, указание fullUser более точно соответствует поведению, заданному пользователем для устройства: если пользователь заблокировал поворот экрана по датчику, приложение следует его настройкам; в противном случае система допускает любую из четырёх возможных ориентаций экрана (книжную, альбомную, перевёрнутую книжную или перевёрнутую альбомную). См. screenOrientation .

2. Определите размер экрана

Настроив манифест на поддержку всех разрешенных пользователем ориентаций, вы можете программно указать ориентацию приложения на основе размера экрана.

Добавьте библиотеки Jetpack WindowManager в файл build.gradle или build.gradle.kts модуля:

Котлин

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Круто

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

Используйте метод Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() для получения размера экрана устройства в виде объекта WindowMetrics . Метрики окна можно сравнить с классами размеров окна, чтобы определить, когда следует ограничить ориентацию.

Классы размеров Windows обеспечивают контрольные точки между маленькими и большими экранами.

Используйте контрольные точки WindowWidthSizeClass#COMPACT и WindowHeightSizeClass#COMPACT для определения размера экрана:

Котлин

/** 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
}

Ява

/** 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;
}
    Примечание:
  • Примеры реализованы как методы действия; поэтому действие разыменовывается как this в аргументе computeMaximumWindowMetrics() .
  • Метод computeMaximumWindowMetrics() используется вместо computeCurrentWindowMetrics() , поскольку приложение может запускаться в многооконном режиме, который игнорирует настройки ориентации экрана. Определение размера окна приложения и переопределение настроек ориентации не имеет смысла, если только окно приложения не занимает весь экран устройства.

Инструкции по объявлению зависимостей для обеспечения доступности метода computeMaximumWindowMetrics() в вашем приложении см. в разделе WindowManager.

3. Переопределить настройки манифеста приложения

Когда вы определили, что устройство имеет компактный размер экрана, вы можете вызвать Activity#setRequestedOrientation() чтобы переопределить настройку screenOrientation манифеста:

Котлин

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
        }
    })
}

Ява

@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);
            }
        }
    });
}

Добавив логику в методы onCreate() и View.onConfigurationChanged() , вы сможете получить максимальные метрики окна и переопределить настройку ориентации при изменении размера или перемещении активности между дисплеями, например, после поворота устройства или при складывании/раскладывании складного устройства. Подробнее о том, когда происходят изменения конфигурации и когда они приводят к повторному запуску активности, см. в разделе Обработка изменений конфигурации .

Ключевые моменты

  • screenOrientation : настройка манифеста приложения, позволяющая указать, как приложение реагирует на изменения ориентации устройства.
  • Jetpack WindowManager : набор библиотек, позволяющих определять размер и соотношение сторон окна приложения; обратно совместим с API уровня 14.
  • Activity#setRequestedOrientation() : Метод, с помощью которого можно изменить ориентацию приложения во время выполнения.

Коллекции, содержащие это руководство

Это руководство является частью тщательно подобранной коллекции кратких руководств, охватывающих более широкие цели разработки Android:

Обеспечьте своему приложению поддержку оптимизированного пользовательского опыта на планшетах, складных устройствах и устройствах ChromeOS.

Есть вопросы или отзывы

Перейдите на нашу страницу часто задаваемых вопросов и ознакомьтесь с краткими руководствами или свяжитесь с нами и поделитесь своими мыслями.
,

Ваше приложение отлично работает на телефонах в портретной ориентации, поэтому вы ограничили его только портретной ориентацией. Но вы видите возможность расширить возможности на больших экранах в альбомной ориентации.

Как можно совместить два варианта — ограничить работу приложения в портретной ориентации на маленьких экранах и включить альбомную ориентацию на больших?

Это руководство является временной мерой, пока вы не улучшите свое приложение, обеспечив полную поддержку всех конфигураций устройств.

Результаты

Ваше приложение сохраняет портретную ориентацию на маленьких экранах независимо от поворота устройства. На больших экранах приложение поддерживает альбомную и портретную ориентацию.

Управление ориентацией приложения

Чтобы включить альбомную ориентацию на больших экранах, настройте манифест приложения на обработку изменений ориентации по умолчанию. Определите размер окна приложения во время выполнения. Если окно приложения небольшое, ограничьте ориентацию приложения, переопределив настройку ориентации в манифесте.

1. Укажите настройки ориентации в манифесте приложения.

Вы можете либо не объявлять элемент screenOrientation в манифесте приложения (в этом случае ориентация по умолчанию будет unspecified ), либо установить ориентацию экрана fullUser . Если пользователь не заблокировал поворот экрана с помощью датчиков, ваше приложение будет поддерживать все ориентации устройства.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

Разница между unspecified и fullUser невелика, но важна. Если значение screenOrientation не указано, система выбирает ориентацию, и политика, используемая системой для определения ориентации, может различаться на разных устройствах. С другой стороны, указание fullUser более точно соответствует поведению, заданному пользователем для устройства: если пользователь заблокировал поворот экрана по датчику, приложение следует его настройкам; в противном случае система допускает любую из четырёх возможных ориентаций экрана (книжную, альбомную, перевёрнутую книжную или перевёрнутую альбомную). См. screenOrientation .

2. Определите размер экрана

Настроив манифест на поддержку всех разрешенных пользователем ориентаций, вы можете программно указать ориентацию приложения на основе размера экрана.

Добавьте библиотеки Jetpack WindowManager в файл build.gradle или build.gradle.kts модуля:

Котлин

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Круто

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

Используйте метод Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() для получения размера экрана устройства в виде объекта WindowMetrics . Метрики окна можно сравнить с классами размеров окна, чтобы определить, когда следует ограничить ориентацию.

Классы размеров Windows обеспечивают контрольные точки между маленькими и большими экранами.

Используйте контрольные точки WindowWidthSizeClass#COMPACT и WindowHeightSizeClass#COMPACT для определения размера экрана:

Котлин

/** 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
}

Ява

/** 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;
}
    Примечание:
  • Примеры реализованы как методы действия; поэтому действие разыменовывается как this в аргументе computeMaximumWindowMetrics() .
  • Метод computeMaximumWindowMetrics() используется вместо computeCurrentWindowMetrics() , поскольку приложение может запускаться в многооконном режиме, который игнорирует настройки ориентации экрана. Определение размера окна приложения и переопределение настроек ориентации не имеет смысла, если только окно приложения не занимает весь экран устройства.

Инструкции по объявлению зависимостей для обеспечения доступности метода computeMaximumWindowMetrics() в вашем приложении см. в разделе WindowManager.

3. Переопределить настройки манифеста приложения

Когда вы определили, что устройство имеет компактный размер экрана, вы можете вызвать Activity#setRequestedOrientation() чтобы переопределить настройку screenOrientation манифеста:

Котлин

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
        }
    })
}

Ява

@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);
            }
        }
    });
}

Добавив логику в методы onCreate() и View.onConfigurationChanged() , вы сможете получить максимальные метрики окна и переопределить настройку ориентации при изменении размера или перемещении активности между дисплеями, например, после поворота устройства или при складывании/раскладывании складного устройства. Подробнее о том, когда происходят изменения конфигурации и когда они приводят к повторному запуску активности, см. в разделе Обработка изменений конфигурации .

Ключевые моменты

  • screenOrientation : настройка манифеста приложения, позволяющая указать, как приложение реагирует на изменения ориентации устройства.
  • Jetpack WindowManager : набор библиотек, позволяющих определять размер и соотношение сторон окна приложения; обратно совместим с API уровня 14.
  • Activity#setRequestedOrientation() : Метод, с помощью которого можно изменить ориентацию приложения во время выполнения.

Коллекции, содержащие это руководство

Это руководство является частью тщательно подобранной коллекции кратких руководств, охватывающих более широкие цели разработки Android:

Обеспечьте своему приложению поддержку оптимизированного пользовательского опыта на планшетах, складных устройствах и устройствах ChromeOS.

Есть вопросы или отзывы

Перейдите на нашу страницу часто задаваемых вопросов и ознакомьтесь с краткими руководствами или свяжитесь с нами и поделитесь своими мыслями.