Vue d’ensemble
Certaines applications sont conçues uniquement pour le mode paysage, par exemple une station caméra sur tablette. Les utilisateurs s’attendent pourtant à ce que l’image soit à l’endroit quelle que soit la façon de poser l’appareil : boutons à gauche ou à droite.
KlugLayout règle l’orientation de l’écran Android sur paysage des deux côtés. L’application reste en paysage, mais pivote de 180 degrés avec l’appareil. Elle indique aussi la rotation actuelle de l’écran, afin qu’une application puisse adapter son propre contenu, comme une image de caméra, à la façon dont l’appareil est tenu.
Les appareils pliables changent d’écran pendant que l’application s’exécute. Un Galaxy Z Fold ou un Pixel Fold est une tablette une fois ouvert et un téléphone une fois fermé ; un Galaxy Z Flip passe de son grand écran principal en hauteur à un petit écran de couverture presque carré. Lorsque l’appareil déplace l’application vers l’autre écran, la scène AIR ne reçoit pas toujours d’événement de redimensionnement, et les valeurs de démarrage pour la taille de l’écran et l’encoche de la caméra restent celles du premier écran. KlugLayout surveille cela nativement et indique à l’application sur quel type d’écran elle se trouve maintenant.
KlugLayout est utilisé chaque jour dans nos applications sur des tablettes Android, notre preuve de concept.
Appareils pliables
KlugLayout classe la fenêtre actuelle dans l’une de trois catégories et envoie un événement à chaque changement de catégorie :
| tablet | Le grand écran. Exemple : un Galaxy Z Fold ou un Pixel Fold ouvert. |
| phone | Un écran de la taille d’un téléphone. Exemple : un Fold fermé, ou l’écran principal d’un Flip. |
| cover | Un petit écran extérieur. Exemple : l’écran de couverture d’un Galaxy Z Flip. |
Lorsqu’un Fold est fermé, le verrouillage en paysage est suspendu pour que l’écran extérieur de la taille d’un téléphone puisse utiliser le mode portrait, et il revient quand l’appareil est rouvert. L’application reçoit aussi la taille et l’encoche de caméra de l’écran actuel : une mise en page construite après le pliage s’adapte donc à l’écran sur lequel elle est affichée.
Dans nos applications, le côté visionnage se déconnecte puis se reconnecte à chaque pliage ou changement d’écran de couverture, afin que les flux en direct démarrent toujours proprement sur le nouvel écran. Sur l’écran de couverture du Flip, l’interface est organisée pour un téléphone normal puis réduite pour s’y adapter.
Testé dans l’émulateur Android avec les profils d’appareil Pixel 9 Pro Fold et Galaxy Z Flip.
iPhone Duo
L’iPhone Duo est le premier appareil pliable d’Apple : un téléphone une fois fermé, une petite tablette une fois ouvert. AIR ne le suit pas de lui-même. Lorsque l’appareil est ouvert, iOS peut maintenir l’application dans sa fenêtre de téléphone avec bandes noires, aucun événement de redimensionnement n’arrive, et les valeurs d’écran au démarrage restent celles de l’écran extérieur.
KlugLayout détecte sous iOS sur quel écran se trouve l’application et envoie le même événement DEVICE_TYPE_CHANGED que sous Android : "phone" lorsque le Duo est fermé, "tablet" lorsqu’il est ouvert. Le même code fonctionne sur les deux plateformes.
État d’avancement : les mises en page de base sont résolues. Les mises en page fermée et ouverte, le pliage et le dépliage pendant l’exécution de l’application, la rotation de l’appareil ouvert et les boîtes de dialogue natives centrées fonctionnent. Les réglages de streaming et de caméra restent à tester sur l’appareil réel.
Inutile d’attendre AIR 52 : à partir d’avril 2027, les envois sur l’App Store devront être compilés avec le SDK iOS 27, et dès lors une application AIR rencontre l’iPhone Duo pour ce qu’il est : un appareil pliable. KlugLayout le gère dès aujourd’hui, avec AIR 51.4.1.
Testé dans le simulateur Xcode 27 (iPhone Duo) avec HARMAN AIR 51.4.1.
Fonctionnalités
- Autonome : une seule ANE, sans bibliothèque centrale ni ANE de dépendance à ajouter
- Paysage des deux côtés, avec rotation suivant l’appareil
- Détection du pliage : tablette, téléphone ou écran de couverture Flip, avec un événement à chaque changement
- iPhone Duo : téléphone une fois fermé, tablette une fois ouvert, avec le même événement que sur Android
- Verrouillage en paysage levé automatiquement tant qu’un Fold est fermé
- Taille et encoche de caméra de l’écran actuel, y compris après le pliage
- Aucun passage en portrait
- Rotation actuelle de l’écran : 0, 90, 180 ou 270 degrés
- Actif dès le démarrage de l’application
- Sans effet sur les autres plateformes : le code peut donc rester dans une application multiplateforme
Plateformes prises en charge
Prise en main
Ajoutez l’extension au descripteur de votre application :
<extensions>
<extensionID>com.klug.layout</extensionID>
</extensions>
Les applications ciblant Android 16 doivent aussi autoriser une orientation fixe sur les grands écrans avec cette propriété, à placer dans <application> des ajouts du manifeste :
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true"/>
Exemples de code
Quatre flux complets, tirés de l’API qui tourne dans nos applications. Les appels retournent immédiatement ; les changements d’écran arrivent sous forme de StatusEvent. Documentation complète →
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 }
Aperçu de l’API
| KlugLayout.getInstance() | Renvoie l’instance unique. |
| isSupported | Vrai sur Android et iOS. Faux ailleurs ; chaque appel est alors sans effet. |
| setSensorLandscape() | Paysage des deux côtés, avec rotation suivant l’appareil. À appeler après stage.setAspectRatio(StageAspectRatio.LANDSCAPE). Android ; sur iOS, LANDSCAPE autorise déjà les deux côtés. |
| displayRotation | La rotation actuelle de l’écran en degrés (0, 90, 180, 270), ou -1. |
| watchFold( stage ) | Commence à surveiller les changements de pliage et d’écran de couverture, même sans verrouillage en paysage. Sur iOS, la scène (stage) est nécessaire pour l’iPhone Duo. |
| isFoldable | Vrai sur le matériel pliable : appareils pliables Android (Android 11 ou version ultérieure) et iPhone Duo. |
| release() | Supprime le verrouillage en paysage, par exemple lorsque l’application passe à une mise en page téléphone. Android ; sans effet sur iOS. |
| deviceClass | La catégorie actuelle : "phone", "tablet" ou "cover" ; "" tant qu’elle est inconnue. Sur iOS, disponible après watchFold(stage) sur l’iPhone Duo. |
| windowWidth / windowHeight | Taille de la fenêtre actuelle en pixels, qui suit l’appareil sur son autre écran ; -1 si elle est inconnue. |
| safeInsetTop | Marge supérieure de l’écran actuel en pixels : l’encoche de caméra sur Android (Android 9 ou version ultérieure), la zone sûre supérieure sur iOS ; -1 si elle est inconnue. |
| DEVICE_TYPE_CHANGED | Code StatusEvent envoyé à chaque changement de catégorie. |
Événements
| deviceTypeChanged | phone · tablet · cover (cover : écran extérieur du Galaxy Z Flip, Android). Envoyé après watchFold(stage), sur Android aussi après setSensorLandscape() ; uniquement lors des changements. |
Acheter KlugLayout
Une licence annuelle pour une application AIR, avec toutes les mises à jour pendant 12 mois. Après le paiement, vous recevez l’extension, la bibliothèque ActionScript et la documentation par e-mail, généralement sous un jour ouvré. Licence et conditions
- Licence pour une application AIR
- Toutes les mises à jour pendant 12 mois
- Sans support
- Licence pour une application AIR
- Toutes les mises à jour pendant 12 mois
- Réponse par e-mail sous 7 jours
- Licence pour une application AIR
- Toutes les mises à jour pendant 12 mois
- Réponse par e-mail sous 48 heures
Prérequis
| SDK AIR | 51.x (HARMAN) |
| Android | Android 6.0 (API 23) ou version ultérieure ; encoche de caméra à partir d’Android 9 (API 28) |
| iOS | iOS 13 ou version ultérieure ; iPhone Duo testé avec AIR 51.4.1 |
| Autorisations | Aucune |