概要
アプリによっては、たとえばタブレット上のカメラステーションのように、横向き専用で設計されています。それでもユーザーは、ボタンが左でも右でも、デバイスの置き方に関わらず映像が正しい向きで表示されることを期待します。
KlugLayout は、Android の画面の向きを両側の横向きに設定します。アプリは横向きのまま、デバイスに合わせて180度回転します。また、現在のディスプレイの回転も報告するため、アプリはカメラ映像などの自身のコンテンツを、デバイスの持ち方に合わせて調整できます。
折りたたみデバイスは、アプリの実行中に画面が変わります。Galaxy Z Fold や Pixel Fold は開くとタブレット、閉じるとスマートフォンになります。Galaxy Z Flip は縦長のメインディスプレイから、小さくほぼ正方形のカバー画面に移ります。デバイスがアプリを別のディスプレイに移しても、AIR ステージにリサイズイベントが届くとは限らず、画面サイズやカメラ切り欠きの起動時の値は最初のディスプレイのままです。KlugLayout はこれをネイティブで監視し、現在どの種類の画面にいるかをアプリに通知します。
KlugLayout は、実証の場である当社のアプリで、Android タブレット上で毎日使われています。
折りたたみデバイス
KlugLayout は現在のウィンドウを3つのクラスのいずれかに分類し、クラスが変わるたびにイベントを送信します:
| tablet | 大きなディスプレイ。例:開いた状態の Galaxy Z Fold や Pixel Fold。 |
| phone | スマートフォンサイズのディスプレイ。例:閉じた状態の Fold、または Flip のメインディスプレイ。 |
| cover | 小さな外側のディスプレイ。例:Galaxy Z Flip のカバー画面。 |
Fold を閉じると横向きロックが一時的に解除され、スマートフォンサイズの外側画面で縦向きを使えるようになり、デバイスを再び開くと元に戻ります。アプリは現在のディスプレイのサイズとカメラ切り欠きも取得できるため、折りたたみ後に構築したレイアウトが、表示されている画面にぴったり収まります。
当社のアプリでは、視聴側は折りたたみやカバー画面の切り替えのたびにサインアウトして再度サインインするため、新しい画面でもライブストリームが常にクリーンに始まります。Flip のカバー画面では、インターフェースは通常のスマートフォン向けにレイアウトされ、収まるように縮小されます。
Android エミュレーターの Pixel 9 Pro Fold と Galaxy Z Flip のデバイスプロファイルでテスト済みです。
iPhone Duo
iPhone Duo は Apple 初の折りたたみデバイスで、閉じるとスマートフォン、開くと小型のタブレットになります。AIR はこれに自動では追従しません。デバイスを開いても、iOS がアプリをレターボックス表示のスマートフォン用ウィンドウに留めることがあり、リサイズイベントは届かず、起動時の画面の値は外側ディスプレイのままです。
KlugLayout は iOS でアプリがどのディスプレイにあるかを検出し、Android と同じ DEVICE_TYPE_CHANGED イベントを送信します。Duo が閉じているときは "phone"、開いているときは "tablet" です。同じコードが両方のプラットフォームで動作します。
ステータス:基本的なレイアウトは解決済みです。閉じた状態と開いた状態のレイアウト、アプリ実行中の折りたたみと展開、開いた状態での回転、中央に表示されるネイティブダイアログが動作します。ストリーミングとカメラの設定は、実機でのテストがまだ必要です。
AIR 52 を待つ理由はありません。2027年4月以降、App Store へのアップロードは iOS 27 SDK でビルドされている必要があり、それ以降は AIR アプリも iPhone Duo を折りたたみデバイスとして認識します。KlugLayout なら、AIR 51.4.1 で今すぐ対応できます。
HARMAN AIR 51.4.1 を使用し、Xcode 27 シミュレーター(iPhone Duo)でテスト済みです。
機能
- 自己完結型:ANE 1つで完結し、コアライブラリや依存 ANE の追加は不要
- 両側の横向きに対応し、デバイスに合わせて回転
- 折りたたみ検出:tablet、phone、Flip カバー画面を判別し、変化のたびにイベントを送信
- iPhone Duo:閉じると phone、開くと tablet。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 から取り出した、4つの完全なフローです。呼び出しは即座に返り、画面の変化は 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 | Android と iOS では true、それ以外では false です。その場合、すべての呼び出しは何もしません。 |
| setSensorLandscape() | 両側の横向きに対応し、デバイスに合わせて回転します。stage.setAspectRatio(StageAspectRatio.LANDSCAPE) の後に呼び出してください。Android 向けです。iOS では LANDSCAPE がすでに両側を許可しています。 |
| displayRotation | 現在のディスプレイの回転角(度。0、90、180、270)。不明な場合は -1。 |
| watchFold( stage ) | 横向きロックなしでも、折りたたみとカバー画面の変化の監視を開始します。iOS では、iPhone Duo のためにステージが必要です。 |
| isFoldable | 折りたたみ対応ハードウェアでは true:Android の折りたたみデバイス(Android 11 以降)と iPhone Duo。 |
| release() | 横向きロックを解除します。たとえば、アプリがスマートフォン用レイアウトに切り替わるときに使います。Android 向けで、iOS では何もしません。 |
| deviceClass | 現在のクラス:"phone"、"tablet"、"cover"。不明な間は ""。iOS では、iPhone Duo で watchFold(stage) の後に利用できます。 |
| windowWidth / windowHeight | 現在のウィンドウのサイズ(ピクセル)。デバイスが別のディスプレイに移っても追従します。不明な場合は -1。 |
| safeInsetTop | 現在のディスプレイの上部インセット(ピクセル):Android ではカメラの切り欠き(Android 9 以降)、iOS では上部セーフエリア。不明な場合は -1。 |
| DEVICE_TYPE_CHANGED | クラスが変わるたびに送信される StatusEvent の code。 |
イベント
| deviceTypeChanged | phone · tablet · cover(cover:Galaxy Z Flip の外側画面、Android)。watchFold(stage) の後に送信され、Android では setSensorLandscape() の後にも送信されます。変化があったときのみ送信されます。 |
KlugLayout を購入
AIR アプリケーション1つ分の年間ライセンスで、12か月間のすべてのアップデートが含まれます。お支払い後、拡張機能、ActionScript ライブラリ、ドキュメントをメールでお送りします(通常は1営業日以内)。ライセンスと条件
動作要件
| AIR SDK | 51.x(HARMAN) |
| Android | Android 6.0(API 23)以降。カメラ切り欠きは Android 9(API 28)以降 |
| iOS | iOS 13 以降。iPhone Duo は AIR 51.4.1 でテスト済み |
| 権限 | なし |