Обзор
Некоторые приложения рассчитаны только на альбомную ориентацию, например станция с камерой на планшете. Но пользователи всё равно ожидают, что изображение будет ориентировано правильно, как бы они ни положили устройство: с кнопками слева или справа.
KlugLayout устанавливает ориентацию экрана Android в альбомную с обеих сторон. Приложение остаётся в альбомной ориентации, но поворачивается на 180 градусов вместе с устройством. Он также сообщает текущий поворот дисплея, чтобы приложение могло подстраивать собственное содержимое, например изображение с камеры, под то, как держат устройство.
Складные устройства меняют экран во время работы приложения. Galaxy Z Fold или Pixel Fold в раскрытом виде — планшет, в сложенном — телефон; Galaxy Z Flip переходит с высокого основного дисплея на маленький почти квадратный внешний экран. Когда устройство переносит приложение на другой дисплей, сцена AIR не всегда получает событие изменения размера, а стартовые значения размера экрана и выреза камеры остаются значениями первого дисплея. KlugLayout отслеживает это на нативном уровне и сообщает приложению, на каком типе экрана оно сейчас находится.
KlugLayout ежедневно используется в наших приложениях на планшетах Android, нашем доказательстве работоспособности.
Складные устройства
KlugLayout относит текущее окно к одному из трёх классов и отправляет событие при каждой смене класса:
| tablet | Большой дисплей. Пример: раскрытый Galaxy Z Fold или Pixel Fold. |
| phone | Дисплей размером с телефон. Пример: сложенный Fold или основной дисплей Flip. |
| cover | Маленький внешний дисплей. Пример: внешний экран Galaxy Z Flip. |
Когда Fold сложен, блокировка альбомной ориентации приостанавливается, чтобы внешний экран размером с телефон мог использовать портретную ориентацию, и возвращается, когда устройство снова раскрывают. Приложение также получает размер и вырез камеры текущего дисплея, поэтому раскладка, построенная после складывания, соответствует экрану, на котором она показывается.
В наших приложениях принимающая сторона выходит из аккаунта и входит снова при каждой смене режима Fold или внешнего экрана, чтобы прямые трансляции всегда чисто запускались на новом экране. На внешнем экране Flip интерфейс строится как для обычного телефона и уменьшается по размеру.
Протестировано в эмуляторе Android на профилях устройств Pixel 9 Pro Fold и Galaxy Z Flip.
iPhone Duo
iPhone Duo — первый складной iPhone от Apple: телефон в сложенном виде, небольшой планшет в раскрытом. AIR сам за ним не следует. Когда устройство раскрывают, iOS может оставить приложение в телефонном окне с чёрными полями, событие изменения размера не приходит, а стартовые значения экрана остаются значениями внешнего дисплея.
KlugLayout определяет на iOS, на каком дисплее находится приложение, и отправляет то же событие DEVICE_TYPE_CHANGED, что и на Android: "phone", когда Duo сложен, "tablet", когда раскрыт. Один и тот же код работает на обеих платформах.
Статус: основные раскладки решены. Работают раскладки в сложенном и раскрытом виде, складывание и раскрытие во время работы приложения, поворот раскрытого устройства и центрированные нативные диалоги. Настройки трансляции и камеры ещё предстоит протестировать на реальном устройстве.
Ждать AIR 52 нет причин: с апреля 2027 года загрузки в App Store должны собираться с SDK iOS 27, и с этого момента приложение AIR встречает iPhone Duo как складное устройство. KlugLayout справляется с этим уже сегодня, с AIR 51.4.1.
Протестировано в симуляторе Xcode 27 (iPhone Duo) с HARMAN AIR 51.4.1.
Возможности
- Автономность: один ANE, без базовой библиотеки и зависимых ANE
- Альбомная ориентация с обеих сторон, поворот вместе с устройством
- Определение складывания: планшет, телефон или внешний экран Flip, с событием при каждом изменении
- iPhone Duo: телефон в сложенном виде, планшет в раскрытом, с тем же событием, что и на Android
- Блокировка альбомной ориентации автоматически снимается, пока Fold сложен
- Размер и вырез камеры текущего дисплея, в том числе после складывания
- Без перехода в портретную ориентацию
- Текущий поворот дисплея: 0, 90, 180 или 270 градусов
- Активно с самого запуска приложения
- На других платформах ничего не делает, поэтому код можно оставить в кроссплатформенном приложении
Поддерживаемые платформы
Начало работы
Добавьте расширение в дескриптор вашего приложения:
<extensions>
<extensionID>com.klug.layout</extensionID>
</extensions>
Приложениям с целевой платформой Android 16 следует также разрешить фиксированную ориентацию на больших экранах с помощью этого свойства внутри <application> в дополнениях манифеста:
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true"/>
Примеры кода
Четыре полных сценария из API, который работает в наших приложениях. Вызовы возвращаются сразу; изменения экрана приходят в виде StatusEvent. Полная документация →
import com.klug.layout.KlugLayout; import flash.display.StageAspectRatio; import flash.events.StageOrientationEvent; var layout:KlugLayout = KlugLayout.getInstance(); // isSupported is false on desktop platforms: every call below is then a no-op, // so this code can stay in a cross-platform app stage.autoOrients = true; stage.setAspectRatio( StageAspectRatio.LANDSCAPE ); // first AIR's landscape ... layout.setSensorLandscape(); // ... then both sides on Android // (on iOS LANDSCAPE already allows both sides) // turn your own content, such as a camera picture, with the device updatePicture(); stage.addEventListener( StageOrientationEvent.ORIENTATION_CHANGE, function( e:StageOrientationEvent ):void { updatePicture(); }); function updatePicture():void { var rotation:int = layout.displayRotation; // 0, 90, 180 or 270; -1 = unknown if ( rotation != -1 ) rotateCameraPicture( rotation ); // your app function }
import flash.events.StatusEvent; layout.addEventListener( StatusEvent.STATUS, onLayout ); layout.watchFold( stage ); // pass the stage: iOS needs it for the iPhone Duo // events report changes only; read the class once for the start var startClass:String = layout.deviceClass; // "phone", "tablet", "cover" or "" (unknown) showLayoutFor( startClass != "" ? startClass : chooseFromStage() ); // your own default function onLayout( e:StatusEvent ):void { if ( e.code != KlugLayout.DEVICE_TYPE_CHANGED ) return; showLayoutFor( e.level ); // "tablet" or "phone"; "cover" on a Galaxy Z Flip (Android) } // fold-only behaviour, kept away from normal phones and tablets if ( layout.isFoldable ) enableFoldHints(); // your app function
function showLayoutFor( deviceClass:String ):void { // size of the current window in pixels, also after the device moved the app // to its other display; -1 = unknown, then fall back to the stage var w:int = layout.windowWidth > 0 ? layout.windowWidth : stage.stageWidth; var h:int = layout.windowHeight > 0 ? layout.windowHeight : stage.stageHeight; // top inset of the current display (Android: camera cutout, from Android 9) var top:int = Math.max( 0, layout.safeInsetTop ); // -1 = unknown if ( deviceClass == "tablet" ) buildTabletViews( w, h, top ); // your app functions else { buildPhoneViews( w, h, top ); if ( deviceClass == "cover" ) scaleToFit( w, h ); // phone layout, scaled down } }
// while a Fold is closed the lock is suspended on its own and comes back when it is opened. // release() is for screens where the app itself leaves landscape (Android; no-op on iOS). function openPortraitScreen():void { layout.release(); // remove the landscape lock stage.setAspectRatio( StageAspectRatio.PORTRAIT ); // AIR decides again } function openStationScreen():void { stage.setAspectRatio( StageAspectRatio.LANDSCAPE ); layout.setSensorLandscape(); // both landscape sides again }
Обзор API
| KlugLayout.getInstance() | Возвращает единственный экземпляр. |
| isSupported | True на Android и iOS. False на остальных; тогда каждый вызов ничего не делает. |
| setSensorLandscape() | Альбомная ориентация с обеих сторон, поворот вместе с устройством. Вызывайте после stage.setAspectRatio(StageAspectRatio.LANDSCAPE). Android; на iOS LANDSCAPE уже допускает обе стороны. |
| displayRotation | Текущий поворот дисплея в градусах (0, 90, 180, 270) или -1. |
| watchFold( stage ) | Начинает отслеживать изменения складывания и внешнего экрана, в том числе без блокировки альбомной ориентации. На iOS для iPhone Duo нужна сцена (stage). |
| isFoldable | True на складном оборудовании: складные устройства Android (Android 11 или новее) и iPhone Duo. |
| release() | Снимает блокировку альбомной ориентации, например когда приложение переключается на телефонную раскладку. Android; на iOS ничего не делает. |
| deviceClass | Текущий класс: "phone", "tablet" или "cover"; "" пока неизвестен. На iOS доступен после watchFold(stage) на iPhone Duo. |
| windowWidth / windowHeight | Размер текущего окна в пикселях, следует за устройством на другой дисплей; -1, если неизвестен. |
| safeInsetTop | Верхний отступ текущего дисплея в пикселях: вырез камеры на Android (Android 9 или новее), верхняя безопасная область на iOS; -1, если неизвестен. |
| DEVICE_TYPE_CHANGED | Код StatusEvent, отправляемый при каждой смене класса. |
События
| deviceTypeChanged | phone · tablet · cover (cover: внешний экран Galaxy Z Flip, Android). Отправляется после watchFold(stage), на Android также после setSensorLandscape(); только при изменениях. |
Купить KlugLayout
Годовая лицензия на одно приложение AIR со всеми обновлениями в течение 12 месяцев. После оплаты вы получаете расширение, библиотеку ActionScript и документацию по e-mail, обычно в течение одного рабочего дня. Лицензия и условия
- Лицензия на одно приложение AIR
- Все обновления в течение 12 месяцев
- Без поддержки
- Лицензия на одно приложение AIR
- Все обновления в течение 12 месяцев
- Ответ по e-mail в течение 7 дней
- Лицензия на одно приложение AIR
- Все обновления в течение 12 месяцев
- Ответ по e-mail в течение 48 часов
Требования
| AIR SDK | 51.x (HARMAN) |
| Android | Android 6.0 (API 23) или новее; вырез камеры — с Android 9 (API 28) |
| iOS | iOS 13 или новее; iPhone Duo протестирован с AIR 51.4.1 |
| Разрешения | Нет |