FlutterでiPhone Duoの折りたたみ状態に対応できるパッケージ「foldable」

Flutterで折りたたみ式デバイスに対応する場合、AndroidではMediaQuery.displayFeaturesなどを利用してディスプレイの折り目やヒンジを扱えます。

一方、iOSではFlutterが折りたたみデバイスのヒンジ情報をそのまま提供していないため、iPhone Duoのような折りたたみ式iPhoneでは、ネイティブ側の情報をFlutterへ橋渡しする必要があります。

「foldable」は、iPhone Duoのヒンジ角度や折りたたみ状態、ディスプレイ上の折り目やカメラ領域などをFlutterから取得できるパッケージです。

foldableとは

foldableは、Appleの折りたたみ式iPhone「iPhone Duo」に対応するためのFlutterパッケージです。

iPhone Duoの状態をFlutterから取得し、以下のような情報をアプリで利用できます。

  • ヒンジの角度
  • 折りたたみ状態
  • 折り目の領域
  • カメラによる占有領域
  • iOSのSize Class
  • 折りたたみ状態に応じたレイアウト変更

パッケージの最新バージョンは1.0.4で、iOS向けに提供されています。

主な特徴

機能内容
ヒンジ角度0〜180度のヒンジ角度を取得
折りたたみ状態closed、partiallyOpen、fullyOpenを取得
リアルタイム監視ヒンジ角度や状態の変化をStreamで監視
FoldAwareBuilder折りたたみ状態に応じてWidgetを再構築
DuoMediaQueryWidgetツリーから折りたたみ情報を取得
Size ClassiOSの画面サイズクラスを取得
折り目領域ディスプレイのヒンジ部分を取得
カメラ領域カメラによる占有領域を取得
MediaQuery連携displayFeaturesへの情報提供をオプションで有効化
非対応端末への対応折りたたみ機構がない端末では安全に無効化

インストール

pubspec.yamlのdependenciesに追加します。

YAML

dependencies:
  foldable: ^1.0.4

その後、Dartコードからインポートします。

Dart

import 'package:foldable/foldable.dart';

iPhone Duoが折りたたみ式か確認する

まず、実行中の端末が折りたたみ式デバイスかどうかを確認できます。

Dart

final isFoldable = await Foldable.isFoldable;

if (isFoldable) {
  print('Foldable device');
}

iPhone Duo以外の端末ではfalseが返されます。

そのため、通常のiPhoneを含むアプリでも条件分岐を入れて利用できます。

ヒンジ角度を取得する

hingeAngleStreamを利用すると、ヒンジの角度をリアルタイムで監視できます。

Dart

Foldable.hingeAngleStream.listen((double degrees) {
  print('Hinge angle: $degrees°');
});

角度は度数で取得されます。

  • 0度:折りたたんだ状態
  • 180度:完全に開いた状態

例えば、ヒンジの開き具合に応じてアニメーションやUIエフェクトを変更するといった使い方ができます。

折りたたみ状態を取得する

ヒンジの角度だけではなく、現在の折りたたみ状態も取得できます。

Dart

final status = await Foldable.hingeStatus;

print(status);

状態として以下が用意されています。

  • closed
  • partiallyOpen
  • fullyOpen

状態の変化を監視する場合はhingeStatusStreamを利用します。

Dart

Foldable.hingeStatusStream.listen((status) {
  print('Hinge status: $status');
});

ヒンジ角度のように連続的に変化する値ではなく、折りたたみ状態が変化したタイミングで通知を受け取れます。

FoldableDataでまとめて状態を取得する

Foldableには、現在の折りたたみ状態をまとめて取得するためのAPIも用意されています。

Dart

final data = await Foldable.snapshot;

print(data);

また、状態変化をFoldableDataとして受け取ることもできます。

Dart

Foldable.changes.listen((data) {
  print(data);
});

ヒンジ角度や折りたたみ状態など、複数の情報をまとめて扱いたい場合に利用できます。

Widgetツリーで利用する

Widgetツリーの中で折りたたみ状態を利用する場合は、FoldableProviderを使用できます。

Dart

FoldableProvider(
  child: MaterialApp(
    home: HomePage(),
  ),
)

FoldableProviderでアプリをラップすることで、その配下のWidgetから折りたたみ情報を取得できるようになります。

FoldAwareBuilderを使う

折りたたみ状態に応じてレイアウトを変更する場合は、FoldAwareBuilderが利用できます。

Dart

FoldAwareBuilder(
  builder: (context, constraints, fold) {
    if (fold.isPartiallyOpen) {
      return const TwoPaneLayout();
    }

    return const SinglePaneLayout();
  },
)

例えば、端末が開いている場合は2ペイン、閉じている場合は1ペインというようにレイアウトを切り替えられます。

折り目を考慮したレイアウト

iPhone Duoの内側ディスプレイでは、中央に折り目となる領域があります。

FoldAwareBuilderから取得できるFoldInfoには、折り目に関する情報も含まれています。

例えば、折り目をまたがないように左右2つの領域へUIを配置できます。

Dart

FoldAwareBuilder(
  builder: (context, constraints, fold) {
    if (!fold.spansDivision) {
      return const SinglePane();
    }

    return Row(
      children: const [
        Expanded(
          child: Leading(),
        ),
        Expanded(
          child: Trailing(),
        ),
      ],
    );
  },
)

これにより、折り目を境界として2ペインのUIを構築できます。

DuoMediaQuery

Widgetツリー内から折りたたみ情報を取得する場合は、DuoMediaQueryも利用できます。

例えば、現在の折りたたみ状態を取得できます。

Dart

final status = DuoMediaQuery.statusOf(context);

ヒンジ角度を取得することもできます。

Dart

final angle = DuoMediaQuery.angleOf(context);

さらに、現在の状態をまとめて取得することもできます。

Dart

final data = DuoMediaQuery.of(context);

DuoMediaQueryはInheritedModelとして実装されているため、必要な情報に依存するWidgetだけを再構築できるようになっています。

Size Classにも対応

foldableでは、iOSのSize Classも取得できます。

例えば、横方向のSize Classを取得します。

Dart

final widthClass =
    DuoMediaQuery.horizontalSizeClassOf(context);

if (widthClass == SizeClass.regular) {
  // 広いレイアウト
}

Size Classには、画面の物理的な幅だけでは判断できないiOSのレイアウト状態が反映されます。

そのため、単純に画面幅だけを基準にするのではなく、iOSが提供するレイアウト情報を使ってUIを切り替えられます。

MediaQuery.displayFeaturesとの連携

foldableには、折り目やカメラ領域をFlutterのMediaQuery.displayFeaturesへ橋渡しする機能もあります。

ただし、この機能はデフォルトでは無効になっています。

これは、パッケージを導入しただけでFlutterの既存のレイアウト動作が変わらないようにするためです。

必要に応じてDisplayFeatureBridgeModeを指定できます。

Dart

FoldableProvider(
  bridgeMode: DisplayFeatureBridgeMode.cutoutsOnly,
  child: MaterialApp(
    home: HomePage(),
  ),
)

利用できるモードには以下があります。

モード動作
nonedisplayFeaturesへ情報を提供しない
cutoutsOnlyカメラなどのカットアウト領域だけを提供
full折り目とカットアウト領域を提供

デフォルトはnoneです。

非折りたたみ端末でも利用できる

foldableは、iPhone Duo以外の端末で利用した場合にも安全に動作するよう設計されています。

折りたたみ機構を持たない端末では、isFoldableがfalseになります。

また、ヒンジ関連のStreamではイベントが発生しません。

そのため、通常のiPhoneを対象としたアプリに導入しても、折りたたみ端末だけを特別に処理できます。

iOS 27.1 SDKとの関係

iPhone DuoのヒンジAPIはiOS 27.1 SDKで提供されています。

一方、foldableは古いSDKでもビルドできるよう、実行時にネイティブAPIを解決する仕組みを採用しています。

そのため、パッケージを利用するだけで特定の新しいXcode環境を必須にする構成にはなっていません。

また、ネイティブAPIを利用できない場合は、その機能を無効化する仕組みが用意されています。

ネイティブAPIの情報を確認する

実行中の環境で利用できるネイティブAPIの情報を確認するためのdebugDumpNativeApi()も用意されています。

Dart

final dump = await Foldable.debugDumpNativeApi();

print(dump);

また、Foldable.capabilitiesから現在利用可能な機能や、その取得方法に関する情報を確認できます。

Dart

final capabilities = await Foldable.capabilities;

print(capabilities);

どのようなアプリに向いている?

foldableは、特にiPhone Duoのような折りたたみ式iPhoneを想定したUIを構築する場合に利用できます。

2ペインUI

折りたたみ状態に応じて、1画面表示から2ペイン表示へ切り替えるUIを構築できます。

折り目を考慮したUI

中央のヒンジ部分を避けて、左右にコンテンツを配置できます。

ヒンジ角度を利用したUI

ヒンジ角度をリアルタイムで取得できるため、端末の開閉に合わせたアニメーションなどに利用できます。

iOSのレスポンシブレイアウト

Size Classを利用して、画面サイズやレイアウト状態に応じてUIを変更できます。

まとめ

foldableは、FlutterアプリからiPhone Duoの折りたたみ機能を扱うためのiOS向けパッケージです。

主に以下の情報をFlutterから取得できます。

  • ヒンジ角度
  • 折りたたみ状態
  • 折り目の領域
  • カメラ領域
  • iOS Size Class
  • 折りたたみ状態の変化

また、FoldableProvider、FoldAwareBuilder、DuoMediaQueryなどを利用することで、折りたたみ状態に応じたレイアウトを構築できます。

iPhone Duo向けにFlutterアプリのUIを最適化したい場合や、折りたたみ状態を利用したレスポンシブなUIを実装したい場合に利用できるパッケージです。

タイトルとURLをコピーしました