Управление окнами

ChromeOS поддерживает приложения Android в нескольких окнах. Система визуализирует приложения в оконные контейнеры, размер которых определяется форм-фактором устройства, как показано на рисунке 1.

Рисунок 1. Окно приложения на разных устройствах.

Важно разрабатывать макеты, подходящие для экранов разных размеров. Если вы следуете рекомендациям Android по поддержке экранов разных размеров , ваше приложение также будет хорошо работать на ChromeOS.

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

Начальный размер запуска

Приложения могут запрашивать первоначальный размер запуска следующими способами:

  • Используйте стартовый размер только в среде рабочего стола. Это помогает оконному менеджеру указать правильные границы и ориентацию. Чтобы указать предпочтения при использовании в режиме рабочего стола, добавьте следующие метатеги внутри <activity> :
<meta-data android:name="WindowManagerPreference:FreeformWindowSize"
           android:value="[phone|tablet|maximize]" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation"
           android:value="[portrait|landscape]" />
  • Используйте статические границы запуска. Используйте <layout> внутри записи манифеста вашей активности, чтобы указать «фиксированный» начальный размер, как в следующем примере:
<layout android:defaultHeight="500dp"
            android:defaultWidth="600dp"
            android:gravity="top|end"
            android:minHeight="450dp"
            android:minWidth="300dp" />
  • Используйте динамические границы запуска. Действие может создавать и использовать ActivityOptions.setLaunchBounds(Rect) при создании нового действия. Указав пустой прямоугольник, ваше приложение можно развернуть.

Изменение размера окон

В ChromeOS пользователи могут изменять размер окна приложения обычным способом: перетаскивая нижний правый угол, как показано на рисунке 2.

Рисунок 2. Окно приложения с изменяемым размером.

Существует два варианта обработки изменения размера окна при использовании класса View :

  • Динамически реагируйте на изменения конфигурации, вызывая onConfigurationChanged(..) . Например, вы можете добавить android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" в манифест действия. Дополнительные сведения об обработке изменений конфигурации см. в разделе Обработка изменений конфигурации .
  • Позвольте системе перезапустить операцию. В этом случае реализуйте onSaveInstanceState и используйте компонент архитектуры ViewModel для восстановления предыдущего сохраненного состояния.

При использовании Jetpack Compose поведение изменения размера зависит от того, как настроено ваше действие. Если он обрабатывает изменения динамически, рекомпозиция запускается при изменении размера окна. Если активность перезапускается системой, после перезапуска происходит первоначальная композиция. В любом случае важно создавать макеты Compose, которые адаптируются к изменяющимся размерам окон. Не предполагайте фиксированных размеров.

Размеры окна

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

Чтобы определить текущую конфигурацию, вызовите getResources().getConfiguration() для текущего действия. Не используйте конфигурацию фоновой активности или системного ресурса. Фоновое действие не имеет размера, а конфигурация системы может содержать несколько окон с конфликтующими размерами и ориентациями, поэтому полезные данные невозможно извлечь.

Обратите внимание, что размер окна и размер экрана не совпадают. Чтобы получить размер окна в DP, используйте Activity.getResources().getConfiguration().screenWidth и Activity.getResources().getConfiguration().screenHeight . Вероятно, вам никогда не понадобится использовать размер экрана.

Границы контента

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

  • Приложения, использующие процесс компоновки Android, автоматически размещаются в доступном пространстве.
  • Нативные приложения должны считывать доступную область и отслеживать изменения размера, чтобы избежать появления недоступных элементов пользовательского интерфейса. Вызовите следующие методы, чтобы определить начальный доступный размер этой поверхности:

    • NativeActivity.mLastContent[X/Y/Width/Height]()
    • findViewById(android.R.id.content).get[Width/Height]()

    Непрерывный мониторинг можно осуществлять с помощью наблюдателя:

    • NativeActivity.onContentRectChangedNative()
    • NativeActivity.onGlobalLayout()
    • Добавьте прослушиватель в view.addOnLayoutChangeListener(findViewById(android.R.id.content))

    Если приложение предварительно масштабирует изображение, делайте это каждый раз при изменении разрешения.

Изменение размера в произвольной форме

ChromeOS позволяет свободно изменять размер любого окна: пользователь может изменить ширину, высоту и положение окна на экране. Многие приложения для Android написаны без учета изменения размера в произвольной форме. Рассмотрите следующие вопросы:

  • Положение экрана может измениться. Всегда используйте систему для выполнения преобразований координат между окнами и экранами.
  • Если вы используете систему просмотра Android, макет вашего окна автоматически меняется при изменении его размера.
  • Если вы не используете систему представлений и не берете на себя управление поверхностью, ваше приложение должно самостоятельно обрабатывать изменения размера.
  • Для собственных приложений используйте элементы mLastContent или используйте представление содержимого, чтобы определить начальный размер.
  • Когда приложение запущено, слушайте события onContentRectChangedNative или onGlobalLayout , чтобы реагировать на изменения размера.
  • При изменении размера приложения измените масштаб или перезагрузите макеты и графические изображения, а также обновите области ввода.

Полноэкранный режим

Полноэкранный режим работает так же, как и на стандартном Android. Если окно не занимает весь экран, запросы на полноэкранный режим (скрытие всех элементов пользовательского интерфейса системы) игнорируются. Когда приложение развернуто, выполняются обычные полноэкранные методы, макеты и функции. Это скроет элементы пользовательского интерфейса системы (панель управления окном и полку).

Ориентация экрана

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

Некоторые приложения Android предполагают, что, когда устройство находится в портретном режиме, значение поворота равно Surface.ROTATION_0 . Это может быть справедливо для большинства устройств Android. Однако, когда приложение находится в определенном режиме ARC , значение поворота для книжной ориентации может отличаться от Surface.ROTATION_0 .

Чтобы получить точное значение вращения при считывании показаний акселерометра или аналогичных датчиков, используйте метод Display.getRotation() и соответствующим образом поменяйте местами ось.

Корневая активность и направленность

Окно Chromebook состоит из стопки окон действий. Каждое окно в стеке имеет одинаковый размер и ориентацию.

Внезапные изменения ориентации и размера сбивают с толку в среде рабочего стола. Оконный менеджер Chromebook позволяет избежать этого, аналогично параллельному режиму Android: действие в нижней части стека управляет атрибутами всех действий над ним. Это может привести к неожиданным ситуациям, когда недавно начатое действие, которое является книжным и не имеет размера, становится альбомным и имеет возможность изменения размера.

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

Рекомендации по ориентации

Следуйте этим рекомендациям по обращению с ориентацией:

  • Если вы поддерживаете только одну ориентацию, добавьте информацию в манифест, чтобы оконный менеджер знал об этом перед запуском приложения. При указании ориентации по возможности указывайте также ориентацию датчиков. Chromebook часто является трансформируемым устройством, и перевернутое приложение неприятно для пользователя.
  • Постарайтесь придерживаться одной выбранной ориентации. Не запрашивайте одну ориентацию в манифесте и не устанавливайте другую позже программно.
  • Будьте осторожны, меняя ориентацию в зависимости от размера окна. Пользователь может застрять в маленьком окне портретного размера и не иметь возможности вернуться к большему окну альбомной ориентации.
  • В Chrome есть элементы управления окнами для переключения между всеми доступными макетами. Выбрав правильный вариант ориентации, вы можете гарантировать, что у пользователя будет правильный макет после запуска приложения. Если приложение доступно в книжной и альбомной ориентации, по возможности установите для него альбомную ориентацию по умолчанию. После установки этой опции она запоминается отдельно для каждого приложения.
  • Старайтесь избегать ненужных изменений ориентации. Например, если ориентация активности является книжной, но приложение вызывает setRequestedOrientation(LANDSCAPE) во время выполнения, это приводит к ненужному изменению размера окна, что раздражает пользователя и может перезапустить приложение, с которым приложение не сможет справиться. Лучше один раз задать ориентацию, например, в манифесте, и менять ее только при необходимости.

Другие соображения

Вот еще несколько вещей, которые следует учитывать при работе с приложениями Android в ChromeOS:

  • Не вызывайте finish() в методе onDestroy вашей активности. Это приводит к тому, что приложение закрывается при изменении размера и не перезапускается.
  • Не используйте несовместимые типы окон, например TYPE_KEYGUARD и TYPE_APPLICATION_MEDIA .
  • Обеспечьте быстрый перезапуск активности за счет кэширования ранее выделенных объектов.
  • Если вы не хотите, чтобы пользователь изменял размер вашего приложения, укажите android:resizeableActivity=false в файле манифеста.
  • Протестируйте свое приложение, чтобы убедиться, что оно правильно обрабатывает изменения размера окна.