Native UI
Native UI は 2.0.0 から正式サポートされています。以前の Native UI Shell Preview はテーマの 1.2.0 と 1.2.1 に同梱されていました。このガイドは分離後のパッケージと改名後の API を説明します。移行を参照してください。アプリ内の拡張は引き続き実験的です。
Native UI は Ionic アプリの Web コンテンツの周囲に、ネイティブのナビゲーションと操作コントロールを提供します。任意の Capacitor iOS プラグインが、対応する固定の Ionic コントロールを UIKit または SwiftUI とシステムの Liquid Glass で描画します。ページ内容、スクロール、アプリの状態、ルーティングは Ionic の WebView に残ります。
DOM とネイティブ表示の共有モデルは投影の仕組みを参照してください。このページは対応コントロールと API のリファレンスです。初回導入と動作例は Ionic のセットアップまたは HTML のセットアップから始めてください。
Native UI を有効にする
iOS テーマを使用中ならテーマに Native UI を追加するに従ってください。その他の Web 外観では Native UI のセットアップを使用します。
Capacitor が検出できるよう、ネイティブパッケージをアプリの直接依存としてインストールします。
npm install @rdlabo/capacitor-native-ui @erkamyaman/capacitor-foldable
npx cap sync ios
既存の Web スタイルを維持し、アプリの起動時に Native UI を一度だけ有効にします。iOS 27 テーマは任意です。
import { enableNativeUI } from '@rdlabo/capacitor-native-ui';
void enableNativeUI();
enableNativeUI() は WebView の実効的な左上の角丸半径も取得して画面遷移に適用します。ネイティブコントロールを有効にせず、遷移だけを設定するには次を呼び出します。
import { configureNativeTransition } from '@rdlabo/capacitor-native-ui';
await configureNativeTransition();
ナビゲーションとネイティブビルド
| 設定 | 操作 |
|---|---|
テーマの iosTransitionAnimation |
維持します。ネイティブとの遷移の調整は含まれています。 |
| Ionic 標準または独自のアニメーション | 遷移アダプターを設定します。 |
| プラグインをインストール・更新したとき | npx cap sync ios を実行し、ネイティブアプリを再ビルドします。 |
| SPM または CocoaPods | 既存の依存管理方法を維持します。両方に対応します。 |
| 任意の CocoaPods から SPM への移行 | npx cap spm-migration-assistant を実行し、生成された CapApp-SPM を Xcode でアプリターゲットにリンクします。 |
| 通常のネイティブガラス表示 | Xcode 26 以降、Capacitor 8、iOS 26 以降が必要です。 |
| Web、Android、SSR、古い iOS | Web 実装を維持します。 |
ページごとの登録、コンポーネント一覧、ネイティブのコールバック、Swift のビューコントローラーは不要です。
明示的に有効にする機能です。通常の @rdlabo/ionic-theme-ios27 エントリーポイントは Capacitor をインポートしません。ネイティブランタイムのエントリーポイントにはブラウザービルドでも @capacitor/core が必要です。Capacitor プロジェクトの直接依存に @rdlabo/capacitor-native-ui があれば、アプリが enableNativeUI() を呼ばなくても Capacitor の同期でネイティブソースが検出・ビルドされます。
ネイティブのライト・ダーク外観は各ソース要素の計算済みスタイルから解決します。テーマの継承、優先順位、動的更新、Vertical Bars の共有動作はライト・ダーク外観を参照してください。
ツールバーの選択とグループ化
controls で配置ごとの選択とグループ化を指定します。
const shell = await enableNativeUI({
controls: {
buttonGroup: 'verticalOnly',
button: true,
backButton: true,
},
});
この例では通常のツールバー操作を個別に投影し、対象のレール操作はグループ化できます。6 つのコントロール項目はすべて true、false、'horizontalOnly'、'verticalOnly' を受け付け、省略時は true です。自動選択するすべてのコントロールをレールに限定するには controls: 'verticalOnly' を使います。完全な表は選択の既定値を参照してください。
button はメニューボタンを含め、グループ内外の通常の操作を選択します。buttonGroup は選択済みの操作だけをグループ化します。buttonGroup: true, button: false では、明示的に選択しない通常の操作は投影されません。backButton は ion-buttons 内も含め、戻る操作を独立して選択します。戻るボタンは通常のグループに加わりません。
ionic.auto は Ionic の自動検出を有効・無効にします。明示的な data-native-ui ソースと拡張は controls および ionic.auto から独立しています。
起動オプションの変更にはランタイムの再起動が必要です。
| 属性 | 適用先 | true |
false |
|---|---|---|---|
data-horizontal-bars |
通常の配置 | 操作を選択、または ion-buttons のグループ化を許可。 |
操作を除外、または ion-buttons のグループ化を無効化。 |
data-vertical-bars |
縦向きレールの配置 | 操作を選択、または ion-buttons のグループ化を許可。 |
操作を除外、または ion-buttons のグループ化を無効化。 |
ボタン・戻るボタンでは選択を、ion-buttons ではグループ化だけを制御します。どちらも継承されません。未指定・不正・空の値には対応する controls の既定値を使います。縦向き操作の明示的な有効化と対象条件は Vertical Barsを参照してください。
<ion-buttons data-horizontal-bars="false" data-vertical-bars="true">
<ion-button fill="clear">First</ion-button>
<ion-button fill="clear">Second</ion-button>
</ion-buttons>
上の水平操作は、他の条件を満たす場合、個別に投影されます。
縦向きの属性はグループ化を許可しますが、テキストだけの子を選択しません。
明示的に選択するには、各ボタンに data-vertical-bars="true" を追加します。
これらの設定は CSS を削除したりソースのレイアウトを変更したりしません。アプリが
ソースグループのガラススタイルを削除する場合、controls: { buttonGroup: 'verticalOnly' } は
共有するネイティブのグループ面も防ぎます。既存のコンポーネントモード、固定ツールバー、
fill/color、Shell の適用除外条件は引き続き適用されます。水平のクリアボタンは
ion-buttons 内で、グループ化を無効にした場合やグループ全体が条件を満たさない場合に
個別に投影できます。戻るボタンは通常のグループには加わりません。
水平のローカル上書きは動的に再評価されます。縦向きの配置は
ページへの訪問ごとの規則を維持します。data-projection="source|system" は別の
ネイティブの縦向き外観の設定です。
単独の enableVerticalControlArea() は controls の既定値が 'verticalOnly' です。明示的ソースと拡張は独立しています。アプリごとに起動エントリーは 1 つだけ使用してください。
対応するマークアップ
以下は通常の Native UI の説明です。Vertical Bars には別のツールバー操作の規則を使用します。
| Ionic コンポーネント | 対応する外観と配置 | ネイティブ描画 |
|---|---|---|
ion-button |
固定ヘッダー・フッターのツールバー内で fill="default"、またはグループ化しない ion-buttons 内の clear |
ガラスの UIButton |
ion-buttons |
固定ツールバー内で、テーマのガラスを共有する直接の clear の ion-button / ion-menu-button が 2 個以上 |
1 つの UIGlassEffect 面と独立したネイティブボタン |
ion-back-button |
固定ヘッダー・フッターのツールバー内で標準のアイコンと色 | 解決済みの Ionic ラベル・アイコンを使うガラスの UIButton |
ion-menu-button |
固定ツールバー内でテーマのガラスを使う ion-buttons の内側 |
ガラスの UIButton。元の Ionic メニュー切り替え |
ion-tab-bar |
固定タブ、アイコンのみ・ラベルのみ、項目ごとにアイコン 1 個、ドット・文字のバッジ、選択・無効状態 | UITabBar と UITabBarItem |
ion-segment |
固定ツールバー内、スクロール不可、項目ごとに文字またはアイコン 1 個 | UISegmentedControl |
ion-fab / ion-fab-button / ion-fab-list |
ion-content の fixed slot 内のガラス FAB。主ボタン 1 個と任意の方向別リスト |
各ボタンに永続するガラスの UIButton、FAB 全体で 1 つの同期グループ |
通常の Native UI では、対応する iOS モードのコンポーネントだけが対象です。テーマ変数は不要で、enableNativeUI() の呼び出しでネイティブ投影を有効にします。明示的に有効にした Vertical Bars は後述のとおりモードから独立しています。要素または祖先の ios-theme-disabled と旧 ios26-disabled は常に除外条件です。タブ・セグメントの 1 項目でテーマを無効にするとグループ全体が Web 表示になります。
ネイティブ投影を除外する
Web テーマを維持して iOS Native UI だけを無効にするには、data-native-ui="disabled"(または同等の native-ui-disabled クラス)を使います。要素とそのすべての子孫を除外します。実行中に属性・クラスを追加・削除すると Web 表示の復元や対象条件の再評価を自動で行います。
正確に disabled を指定した場合のみ除外し、空や未知の値では除外しません。自動 Ionic 投影へ戻すには属性を削除します。明示的な HTML コントロールでは元の data-native-ui="button" または data-native-ui="back-button" に戻してください。親に data-native-ui="disabled" を付けると子の宣言を残して部分木を無効にできます。native-ui-disabled クラスもあれば削除してください。クリックや Web テーマは無効にしません。ランタイム所有の data-native-ui-projected マーカーは別物で、アプリ側では設定しないでください。以前の除外属性は移行を参照してください。
<ion-toolbar data-native-ui="disabled">
<ion-button>Web glass button</ion-button>
</ion-toolbar>
通常の配置では、共有面内の data-native-ui="disabled" または .native-ui-disabled が、その面と子全体を Web 表示にします。ボタングループ、タブバー、セグメント、FAB リストも対象です。buttonGroup によるグループ化の無効化とは異なります。検索 FAB または検索フッターの一部を除外するとネイティブ検索連携は無効になりますが、タブバー自体は対象条件を満たせばネイティブ表示できます。
配置の要件
ガラスの外観だけでは対象になりません。通常の投影には固定されたコントロールが必要です。
| コントロールまたは位置 | 対象条件 |
|---|---|
| ボタン、戻るボタン、メニューボタングループ、セグメント | ion-header または ion-footer 直下のツールバー内で、コントロールの祖先に ion-content がないこと。 |
| ヘッダー・フッター直下のボタン、単独のツールバー、スクロール内容内のツールバー・ヘッダー | Web 表示を維持。 |
| FAB | ion-content の fixed slot が必須。 |
.ios-theme-vertical-bars 有効時の戻るボタン |
ルーティングされた内容や常設のアプリ Shell を含め、固定ツールバー外でも投影可能。Vertical Bars は ios モードを要求しません。 |
| 折りたたまれたヘッダー、除外されたコントロール、離脱したページ | 対象外。 |
| 最前面の全幅モーダル | Vertical Bars に参加可能。他のオーバーレイ面は固有のレイアウトを維持。 |
投影中のコントロールを対象外の位置に移すと Web 表示に戻り、戻すと再評価します。Vertical Bars を有効にする場所と Ionic コンポーネントのモードはアプリが選択します。
タブのレイアウト
| ソースのレイアウト | 結果 |
|---|---|
等幅の項目で既定の layout="icon-top" |
iPad や横向きも含め、アイコン・ラベルを縦に並べたネイティブレイアウト。 |
icon-start、icon-end、icon-bottom、icon-hide、label-hide |
タブバー全体が Web 表示。 |
| 項目の幅が不均等 | タブバー全体が Web 表示。 |
| 始端・中央・終端の配置 | RTL を含めソースのバーに追従。 |
方向性のある ion-icon |
描画済みの RTL 反転を維持。 |
ネイティブバーはアプリの size class を変更せず、ローカルの水平 compact・垂直 regular の size class を使用します。ラベルのサイズと太さは Web スナップショットに従います。
通常のボタンのグループ化
以下は Vertical Bars 以外に適用されます。
| ソースまたは設定 | 結果 |
|---|---|
ion-buttons 内の clear ボタン |
個別に投影可能。 |
| 単独の clear、solid、outline ボタン | Web 表示を維持。 |
| グループ化が有効で、対象の clear ボタンが 2 個以上 | 1 つのネイティブ面に独立した操作。メニューボタンも参加可能。 |
| 単一のメニューボタン | 親グループを面として使用。 |
| グループ化が無効、fill が混在、非対応の子がある | 対象の操作は個別に投影可能。明示的な部分木の除外には前述の共有面の規則を適用。 |
| 戻るボタン | 通常の操作グループには参加しません。 |
非対応の内容
以下は Web 表示を維持します。プラグインは任意のアプリ CSS を UIKit スタイルへ変換しません。
| 対象 | 非対応の設定 |
|---|---|
| ボタン | 独自のボタン色や、独自の戻るアイコン・色。 |
| コンテナー | 折りたたみヘッダー、スクロール内容内のツールバー、通常のモーダル内容。Vertical Bars のモーダルは後述の別規則を参照。 |
| セグメント | スクロール・展開セグメント、segment-view 連携。 |
| 内容 | 複雑な slot、非対応の SVG 機能。 |
背景とフォールバックの切り替え
ネイティブガラスは実際に背後に描かれた Web 内容を取り込みます。既存のツールバー背景やヘッダーのぼかしも影響します。ヘッダーの背後を内容がスクロールするには、Ionic 標準の半透明ヘッダーと全画面コンテンツのレイアウトを使ってください。プラグインはページ内容を移動せず、アプリが指定した不透明なツールバー背景も上書きしません。
Web 入力がソフトウェアキーボードを使用中は通常のコントロールを Web 表示へ戻し、閉じると再評価します。キーボードで visual viewport が動かない iPad のレイアウトも対象です。ネイティブ検索欄は自身のネイティブキーボードと検索面を維持します。
既存のコントロールが非対応になると、ネイティブの覆いを削除する前に Web ソースを描画します。空白の切り替えを避けますが、Web/UIKit の更新は不可分ではないため、一瞬重なる場合があります。変更のない共有ネイティブタブを維持する通常のページ遷移とは異なる境界動作です。
状態とイベント
メニュー操作
メニューボタンは Ionic が解決した既定・設定済みアイコン、または対応する slot アイコン・ラベルを使います。ネイティブ操作は元の ion-menu-button をクリックし、menu の対象指定を維持します。標準以外の type(submit / reset)は Web 表示です。disabled、autoHide、メニューの利用可否、分割ペインの表示は実際の DOM に従います。メニューを開くと Web コントロールを復元してネイティブの覆いを終了し、閉じると対象コントロールを再投影します。
タブの形状と状態の更新
ラベル、SVG 内容、配置、選択値、アプリの動作は DOM が管理します。配置基準は ion-tab-bar 自体で、内部余白とプレートのサイズは UIKit が管理します。
| ソースまたはビューポート | ネイティブの動作 |
|---|---|
| ソースバーの矩形 | UIKit のより大きな外枠を考慮したサイズ提案と配置の基準。 |
tab-bar-position-start、tab-bar-position-center、tab-bar-position-end |
RTL を含む水平の基準。クラス変更は自動反映。 |
slot="bottom" / slot="top" |
対応する下端・上端を維持。 |
| 対応する縦積みレイアウトとラベル書体 | Web スナップショットに追従。fill 配置でも UIKit が内容幅を制限する場合があります。 |
| バッジ・タイトルの更新 | ネイティブ項目の同一性を維持し、同じ基準で再計測。 |
| ネイティブの幅・高さの相違 | 投影を拒否しません。CSS 項目幅へ無理に合わせてアイコンを伸ばしません。 |
| 認識できないネイティブレイアウト | Web 表示を復元。 |
Web テーマの標準的な外観の目標値:
| 計測対象 | 目標 |
|---|---|
| ビューポート幅 768px 以上、タブ数 2 / 3 / 4 / 5 | プレート幅はそれぞれ約 188 / 274 / 336 / 414pt。より狭い場合は電話用のサイズを維持。 |
| バーの高さ | 62pt |
| 選択部分の高さ / インセット | 54pt / 4pt |
| 隣接ボタン | UIKit コントロールと同様に重なる。 |
独自のフォント・アイコン・ラベルの完全一致は保証しません。固有幅は UIKit が決定します。アイコンとラベルの位置はシミュレーター画像で確認しています。プラグインは非公開クラス名や固定のインセット補正を使わずにネイティブタブの部分木を計測します。
ランタイムは以下を再確認します。
- 構造の変更、影響する shadow root、サイズ。
- ページのライフサイクルイベントとオーバーレイ。
- 祖先の
display: none、hidden、テーマクラス、コンポーネントの削除と無効状態の変更。
ネイティブタッチイベントは、元の Ionic 要素をクリックする前に現在の DOM とリビジョンで検証します。
フォームとセグメントの値
フォームでは ion-button type="submit" と既存の submit ハンドラーを維持します。外部フォームも引き続き [form]="formRef" で渡します。プラグインは form.submit() の呼び出し、別の送信経路の追加、Angular のフォーム管理の変更を行いません。元の ion-segment-button をクリックするため、セグメントの値は元の型を維持します。プログラムによる値の変更で合成の ionChange は発火しません。
テキストと画像
ラベルはネイティブテキストです。ローカルの静的 SVG と解決済みの ion-icon SVG(name と name の変更を含む)は表示倍率でラスタライズし、キャッシュします。source 投影は色を維持し、縦向きツールバーボタンの system 投影は SwiftUI が着色するテンプレートアイコンを使います。文字色に従うタブ SVG はネイティブのテンプレート描画で、ブリッジの画像更新を待たずラベルと同時に選択色が変わります。多色タブ画像は元の色を維持します。外部参照、<use>、アニメーション、埋め込み HTML・画像、SVG テキスト、スタイルシートは対象外です。Web フォントや任意の slot レイアウトは完全には再現しません。
タッチ、バッジ、アクセシビリティー
ネイティブホストはコントロール内だけで入力を受け付けます。タブ操作とアクセシビリティーは標準の UITabBar が提供し、空白領域のタッチは WebView に通します。Ionic iOS は既定で空のバッジを非表示にします。空でも表示中の ion-badge はネイティブの通知ドットになり、内容があれば文字を表示します。背景色と文字色は Ionic の color パレットを含む計算済み DOM スタイルから取得します。非表示・削除したバッジはネイティブからも消えます。タブは UIKit 標準のタブコントロールで選択、タッチ、バッジ、アクセシビリティーを処理し、選択更新時も項目の同一性を維持します。計測したバー内の項目配置は UIKit が管理するため、任意の CSS 配置は再現しません。ネイティブコントロールは名前、無効・選択の特性、バッジをアクセシビリティーに公開し、投影中のソースは Web アクセシビリティーから隠します。Web と UIKit の VoiceOver 巡回順序の完全一致を保証するものではありません。
検索可能なタブ
既存の attachTabBarSearchable(tabBar, fabButton, footer) 登録は、下部タブバーとガラスの検索コントロールが対応条件を満たすと自動的にネイティブ検索を使います。新しいコンポーネントオプション、ルート、ネイティブ設定、ページリスナーは不要です。通常のタブバーは UITabBar、水平の検索グループは永続する UITabBarController、UITab / UISearchTab、UISearchController を使います。結果表示とナビゲーションは元の Capacitor WebView が担当します。
Vertical Bars ではネイティブレールがすべてのタブと選択を維持します。SwiftUI の searchable と searchToolbarBehavior(.minimize) が同じネイティブのナビゲーション面にシステムの検索ボタン、入力欄、閉じる操作、遷移を提供します。配置は現在のデバイスレイアウトに応じて Apple が決定し、システム検索を開くとネイティブ欄にフォーカスします。入力、フォーカス、クリア、送信は水平検索と同じブリッジです。Vertical Bars を有効にすると、Web 投影は登録済みの検索ボタンを表示中の縦タブの上に、タブ非表示時はレールの下に置き、操作を元の FAB に転送します。ネイティブ検索が利用可能なら Web 投影を置き換えます。Web 検索表示も縦タブを維持します。
検索の登録は配置制約を回避しません。検索バーと閉じるボタンは固定フッターツールバーに置く必要があります。トリガーは ion-content 直下の ion-fab[slot="fixed"] 内、または既存のスクロールしない .ion-page レイアウトの直下に置きます。スクロール内容内のラッパーは fixed slot ではありません。
水平タブでは対応する検索レイアウトを計測できると、登録が有効な間、遷移中や一時利用不可(available: false)でも検索コントローラーを維持します。非表示ページでの初回登録は検索コントロールを計測できるまで通常のタブを維持します。同じコントローラーが通常時と検索中を管理します。通常時はビューを元の ion-tab-bar に合わせ、タブプレートのソース幅を維持します。小さいタブグループでは UIKit がプレート幅を制限する場合があります。タブ横の検索ボタンの配置は UIKit が管理します。水平検索グループをソースレイアウトに合わせられない場合、検索は Web に残ります。対象のタブは Web 検索トリガーを覆わない限りネイティブを維持し、重なる場合は Web に残ります。遷移先ページの表示完了前(例: ionViewWillEnter)に登録してください。検索コントロールを計測でき次第、投影を開始します。
検索を開いても Ionic の選択タブを維持し、キーボードは自動表示しません(automaticallyActivatesSearch はオフ)。入力欄をタップするか ion-searchbar.setFocus() を呼び出してください。検索中は Web レイアウトの投影を固定し、Capacitor Keyboard の resize を none に保ちます。UIKit がタブ・検索 UI を管理し、その間のフレーム調整は行いません。閉じると通常のタブをソース位置へ戻します。通常のネイティブタブは Web の selected が追いつくまで先行した選択を維持します。入力イベントとアプリの value 更新は閉じるまでブリッジで継続します。トリガーの解決済み SVG、アクセシビリティーラベル、検索アイコンは ion-icon name を含め Ionic から投影します。
ネイティブ編集は Ionic の入力ハンドラーを経由し、ionInput の debounce、ionChange、ionFocus、ionBlur、ionClear を維持します。プログラムによる value 変更は ionInput を発火せず、アプリの同期的な補正と古いネイティブ入力を区別します。変換中の文字列とキャレットはネイティブ編集が管理します。フッターの閉じる操作で戻ると値を維持し、ionCancel や ionClear は発火しません。
対応する検索設定
| 項目 | ネイティブ対応 | Web 表示を維持 |
|---|---|---|
| 検索グループ | iOS モードのガラス検索バーを持つ登録済み検索タブ。 | 一般の単独検索バー、従来型の検索バー。 |
| キーボードと文字設定 | 標準の検索キーボードと既定の自動修正・大文字化。 | 独自の入力モード、return キーのヒント、最小・最大長、autocomplete、自動修正、スペルチェック設定。 |
| クリア・キャンセル操作 | 既定のクリア操作、内部キャンセルボタンなし。 | 独自のクリアアイコン、内部キャンセルボタン。 |
| 状態とフォーカス | disabled、placeholder、value、setFocus() を同期。 |
非対応のグループ構成は Web 表示。 |
検索の寿命と復旧
ページの終了、オーバーレイ、テーマ除外、ネイティブ所有権の喪失でネイティブ表示を閉じ、最新の同期済み値・アプリ値を維持します。次の検索は閉じた状態から始めます。登録はキャッシュされたページ遷移を越えて維持され、戻るたびの再登録は不要です。ブリッジ待機には上限があります。開く要求でブリッジが失われると、保留中の Enter は既存の Web アニメーションで完了できます。JavaScript に届いていないネイティブ文字は切断したブリッジから復旧できません。
登録済みの ion-searchbar または入力を置き換えると古い編集セッションを終了します。新しい要素は自身のアプリ値を維持し、再度開くと新しいネイティブセッションを開始します。
有効中は、Ionic がすでにヘッダー境界を描くため WebView 上端のスクロールエッジ効果を抑制します。OS と Web テーマが異なるときの二重の暗いグラデーションを防ぎます。破棄時に元の設定を復元します。
ネイティブ検索コントローラーは自身のキーボードより上に表示され続けます。Web 入力がキーボードを開く間、他の投影コントロールは非表示です。標準コントロールには UIKit 自身のアクセシビリティーとReduce Motion(視差効果を減らす)が適用されます。VoiceOver 巡回全体の同等性は検証済みの保証ではありません。
FAB の動作
FAB は Ionic の activated、各子の show、close()、元のクリックハンドラーを維持します。複数リスト、初期展開、小型ボタン、edge は各ボタンの計測レイアウトを使います。ネイティブ側は別のタイマーや開閉制御を加えず、Ionic の段階的表示を反映します。主ボタンのアイコン変更は解決済みの closeIcon でクロスフェードし、Reduce Motion(視差効果を減らす)では無効です。ネイティブ FAB ボタンのインスタンスは開閉更新を通じて維持し、通常の開閉中もソース FAB の投影を続けます。
FAB の対象条件
非対応の子が 1 つでもあれば、リストが閉じていても FAB 全体が Web 表示になります。
| 項目 | 対応 | Web 表示を維持 |
|---|---|---|
| 外観 | 標準の円形ガラス。 | 色付きの塗りつぶしボタン、独自ホスト背景・形状・動き。 |
| 内容 | 文字と解決済みの静的 SVG / ion-icon(RTL 反転を含む)。 |
非対応の画像。 |
| 操作 | 元のクリックハンドラー。 | submit/reset または href の FAB。 |
| 配置 | ion-content 直下の子に slot="fixed"。 |
非固定配置、ページの兄弟に指定した slot="fixed"。 |
たとえばデモの赤い背景の floating-action-button-fixed ページは Web の外観を維持します。
FAB、リスト、ボタンに独自のホストアニメーションや transition があると、削除するまでグループは Web に残ります。ボタンの transform は標準の恒等変換と非表示の子の scale(0) に対応し、独自の拡大縮小は非対応です。display:none のリスト内では、独自の transform があっても計算値が none になる場合があります。レイアウト取得時に検証し、必要なら FAB 全体を Web へ戻します。非表示レイアウトを予測するためにアプリのスタイルシートを解析したり、一時的にリストを開いたりはしません。
遷移と復旧
組み込みの iosTransitionAnimation はネイティブ表示の終了を待ってから Web アニメーションを開始します。終了処理中の対話的な進行、完了・キャンセルはキューに入れます。位置が変わらない共有タブは維持します。初回描画とアニメーションビルダーのない遷移は起動ランタイムと Ionic ライフサイクルイベントで処理します。Ionic 標準・独自ビルダーも @rdlabo/ionic-theme-ios27 の withNativeUITransition() で同じ連携を使えます。ナビゲーションアニメーションの接続を参照してください。
通常のネイティブ/Web の切り替えは、Vertical Bars の両方向も含め 180ms の不透明度クロスフェードを共有します。終了する表示は入力もアクセシビリティーフォーカスも受けません。Reduce Motion(視差効果を減らす)とモーダル表示では即時切り替え、検索コントローラーは UIKit 管理の遷移を維持します。
タブ切り替えでは終了中の UIKit スナップショットが次のタブを覆わないよう、Web/ネイティブのクロスフェードを省略します。ionViewWillLeave でルーター URL と選択中のタブを比較して検出します(素の ionTabsWillChange / ionTabsDidChange DOM イベントも使用)。スタックの push/pop は通常の 180ms の切り替えです。
標準の Ionic オーバーレイは、閉じるまで通常のネイティブ投影を中断します。Vertical Bars は別の規則です。
| 面または条件 | Vertical Bars の動作 |
|---|---|
| Web トースト、通常のポップオーバー、従来型 picker オーバーレイ | ネイティブレールの表示・更新・操作を維持。 |
| Vertical Bars ボタンから開いた Web 描画のポップオーバー | ネイティブ拒否や準備失敗も含め、閉じるまでレールを Web 投影へ戻す。 |
| アラート、アクションシート、loading | オーバーレイと暗い背景が正しく覆うよう Web 表示を復元。 |
| メニュー | 既存のネイティブレール動作を維持。 |
| 最前面の全幅モーダル | 覆われたページの代わりにモーダルのコントロールを投影。 |
| Vertical Bars を利用できないモーダル | Web 表示を復元。 |
| 明示的中断、利用不可のネイティブレイアウト、非表示ドキュメント、非対応のキーボード・ビューポート形状 | 既存のフォールバック動作を維持。 |
Web 表示を要求するすべてのオーバーレイが閉じてからネイティブ投影を再開します。後述の任意のネイティブ Vertical Bars ポップオーバーは自身の SwiftUI 表示と入力処理を維持します。非対応の検索タブ構成は既存の Web アニメーションを使い、Web ガラスジェスチャーと所有権を共有します。対応する包含面の CSS アニメーション中も一時的に Web 表示になります。
終了時はソースを復元し、描画を許可してからネイティブの覆いを削除します。取得時は有効な最新のネイティブ応答が成功してからソースを隠します。遅延応答はコントロールごとに再検証し、既存の対象コントロールは内容更新を待つ間ネイティブの覆いを維持します。削除・対象外のソースだけが Web に戻り、新しいソースには厳密な確認応答が必要です。通常のページ変更は全体 clear を呼びません。UIKit のタブと項目を維持し、同じフレーム・選択は再適用せず、重複・古い操作は破棄します。WebKit と UIKit の描画は別々です。意図的な空白フレームは避けますが OS レベルの不可分な合成を保証しません。導入前に独自の遷移やオーバーレイを対応シミュレーターで確認してください。未知のオーバーレイシステムは自動連携の契約外です。
ブリッジ更新の失敗・タイムアウトではネイティブ投影を停止し、Web 表示を復元します。自動再接続はしません。getStatus().reason に失敗理由が入り、Web フォールバック中の公開ハンドルは stopped ではなく state: 'web' を返します。再試行するにはそのハンドルを destroy() してから enableNativeUI() を再度呼びます。
起動時の必須ブリッジ呼び出しが失敗・タイムアウトした場合は Web フォールバックのハンドルを返します。任意の WebView メトリクスの失敗はネイティブコントロールを無効にしません。destroy() は終了処理を待ち、繰り返し呼び出しても完了を共有します。終了処理中の新しい有効化は、destroy() を await していなくても完了を待ちます。次の操作がクリーンアップに依存する場合はこれらの Promise を await し、拒否を処理してください。
診断やアプリ終了時:
const shell = await enableNativeUI(); // 繰り返し呼び出してもランタイムを共有します
console.log(shell.getStatus()); // 状態、投影コントロール数、更新数、失敗理由
await shell.destroy(); // DOM を復元し、ネイティブコントロールを削除してリスナーとキャッシュを解放します
投影は起動 API の呼び出しで有効になります。部分設定は既定値を上書きします。
const shell = await enableNativeUI({ controls: { tabs: false } }); // タブ以外の Ionic を自動投影します
await shell.disableVerticalControlArea(); // 通常のネイティブコントロールを維持します
await shell.enableVerticalControlArea();
await shell.destroy(); // すべての投影を停止します
既定値、レールのみの利用、ライフサイクルメソッドは全設定オプションを参照してください。Ionic なしの明示的 HTML ソースはフレームワーク非依存の設定を参照してください。
Vertical Bars に固定するポップオーバー
ネイティブのポップオーバー表示は Vertical Bars 専用です。 ネイティブ Vertical Bars が受理した ion-button アンカーが必要です。ionic.verticalBars.popover を有効にしても通常のツールバーや本文のポップオーバーはネイティブになりません。Native UI 全体を有効にせず、単独の Vertical Bars ランタイムでも利用できます。
ionic.verticalBars.popover を有効にすると、受理されたネイティブ Vertical Bars の ion-button からポップオーバーを表示します。Ionic ボタンの自動投影は既定で有効です。ionic.auto が false の場合は個別のアンカーに data-native-ui="button" を指定してください。
await enableNativeUI({
ionic: { verticalBars: { popover: true } },
});
同じオプションは enableVerticalControlArea() でも使えます。投影ボタンを trigger で指定する ion-popover、またはボタンのクリックイベントを渡す PopoverController.create({ event, ... }) を使用します。ボタンがネイティブ Vertical Bars に受理されている必要があります。通常のツールバーボタン、本文のコントロール、存在しない・拒否されたアンカーは Ionic の Web 表示を維持します。
Vertical Bars を Web 表示へ戻す際は、現在のネイティブの戻るボタン、ツールバー操作、タブ面を終了前に計測します。Web フォールバックはその矩形で描画してからネイティブを削除します。計測値はソース要素とビューポートに紐づき、取得できなければ CSS レイアウトを使います。配置とサイズは揃いますが、Web のガラスやアイコンの描画はシステム素材と異なる場合があります。
ページのネイティブコントロールは準備・表示・終了を通じて投影を維持します。Ionic の終了中に同じネイティブアンカーがタップを受理すると、1 操作を保持し、クリーンアップ後に再検証します。連打はまとめます。中継は Ionic の内容初期化中に子 WebView を準備し、非表示ソースホストの背後で動きなしに Web の入場アニメーションを完了し、ボタン標準の SwiftUI ポップオーバーで表示します。ソース WebView のサイズ変更や親の変更はしません。Ionic はコントローラー、ライフサイクル、ライブのハンドラー、終了データを維持し、実際の内容だけが一時的に子ドキュメントへ移動して終了時に復元されます。
同時に中継できるポップオーバーは 1 つです。子ドキュメントで作った入れ子のポップオーバー・モーダルは、中継内容の外に追加されたものも含め、子が閉じる前に実要素のままソースドキュメントへ戻します。ハンドラーと終了データを持つ Web オーバーレイとして続き、表示イベントは再実行しません。別のオーバーレイやメニューを開く、ページを離れる、Shell を中断する、ネイティブレイアウトを失うと Web 表示へ戻ります。モーダル、シート、アラートの中継は対象外です。
矢印、角丸、アニメーションはネイティブが管理し、独自の Web enter/leave アニメーションでは置き換えません。ソースの enter ビルダーは子も含め時間と遅延 0 で一度実行し、既定の reference="trigger" ではネイティブアンカーの矩形と Web フォールバック用の表示状態を使います。明示的な reference="event" は Ionic のイベント座標の意味を維持します。明示的な enterAnimation を優先し、なければこのパッケージの iOS ポップオーバービルダーを使います。独自ビルダーにはグローバルな popoverEnter に頼らずオーバーレイの enterAnimation を設定してください。Material Design(md)のポップオーバーは Ionic の Web 表示です。初期の内容サイズは Ionic が決定します。
ポップオーバーのフォールバック条件
中継はドキュメントとポップオーバーの shadow スタイルをコピーし、内容の境界余白を維持します。表示前にソースの寸法で主要な計算済みレイアウト・外観プロパティを比較します。
| 条件 | 結果 |
|---|---|
| スタイル・レイアウトの相違を検出 | 実際の Web ポップオーバーを復元。 |
| 非対応の祖先の視覚効果・サイズコンテナー | 実際の Web ポップオーバーを復元。 |
| 内容が 1,000 要素を超える | 実際の Web ポップオーバーを復元。 |
| 複製した祖先属性やソース head のスタイルが変更 | Web 表示を復元。 |
| 準備失敗、またはネイティブアンカーが利用不可 | Web ポップオーバーを復元。 |
レールボタンのポップオーバーが Web へ戻ると、閉じるまでレールも Web 投影へ戻ります。この互換性確認は、任意の CSS(疑似要素・動的 CSSOM 変更を含む)、ドキュメント依存のクエリー、VoiceOver・物理キーボードの完全な同等性を保証しません。
独自オーバーレイでの中断
Native UI が検出できない独自モーダル・オーバーレイは、表示前に中断を取得します。中断の Promise が解決した時点で投影コントロールは Web に戻っています。閉じた後は必ず解放してください。
const suspension = await shell.suspend();
try {
await modal.present();
await modal.onDidDismiss();
} finally {
await suspension.resume();
}
中断は入れ子にでき、resume() は冪等です。すべての中断を解放してから、古いスナップショットではなく現在の DOM を使ってネイティブ投影を再開します。
ネイティブ素材とコントロールの外観は実行中の iOS バージョンに従います。テーマをインストールするだけで iOS 26 デバイスが iOS 27 の外観になるわけではありません。
iPhone Duo への対応
単独の Vertical Bars を含め、iPhone Duo 対応は 2.0.0 から安定版です。
単独の Vertical Control Area エントリーポイント(@rdlabo/capacitor-native-ui/vertical-bars)はアプリが提供する Web レイアウトで動作します。テーマの任意のレールスタイルシート @rdlabo/ionic-theme-ios27/dist/css/vertical-bars.css は、iOS 27 の外観全体なしで利用できます。この用途では enableNativeUI({ controls: 'verticalOnly' }) を呼び、縦領域に配置したコントロールを選択します。すでに enableNativeUI() を呼ぶアプリは両方を起動せず、単一ランタイムを維持してください。Shell を使わないアプリのヒンジ状態・分割ペインも含む設定はデバイスレイアウトと分割ペインを参照してください。
Vertical Bars はシステムレール内で SwiftUI の TabView とツールバーを使います。ラベル、アイコン、選択・無効状態、操作の正は引き続き Ionic です。レールのレイアウト、ネイティブのフォールバック、対応オーバーレイは Vertical Barsを参照してください。
Vertical Bars で固定ツールバーの ion-button を自動選択するには、slot="icon-only" の ion-icon または SVG が必要です。その他の対応ボタンは data-vertical-bars="true" で明示的に選択できます。すべての fill と Ionic カラーが対象で、送信ボタンも同じ配置規則です。水平のままにするにはボタンまたは ion-buttons グループに .ios-theme-horizontal-only を追加します。ツールバー操作を参照してください。
ネイティブボタンの外観: 縦向きネイティブボタンの既定値は buttonProjection: 'system' です。Ionic の fill と色を投影するには source を使います。ローカルの例外は data-projection="source|system" または同等の ios-theme-projection-source / ios-theme-projection-system クラスで指定します。対象はネイティブの縦向き ion-button と ion-menu-button だけです。水平コントロールと Web の複製は従来の動作を維持します。優先順位と fill の規則はボタンの外観の選択を参照してください。
既存テーマを維持する単独設定は既存のテーマで iPhone Duo に対応するを参照してください。
Native UI API
以下の生成リファレンスは enableNativeUI() が返すハンドルの説明です。内部の Capacitor ブリッジとコントロールスナップショットのプロトコルは実装詳細です。
<docgen-index>
enableVerticalControlArea()disableVerticalControlArea()markForCheck()getStatus()suspend()destroy()- インターフェース
</docgen-index>
<docgen-api>
実行中の Shell。配置の変更は他の起動設定をすべて維持します。
enableVerticalControlArea()
enableVerticalControlArea() => Promise<void>
利用可能な場合にレール投影を有効にし、他の設定を維持します。破棄後は拒否します。
disableVerticalControlArea()
disableVerticalControlArea() => Promise<void>
通常のネイティブコントロールを停止せず、レールのソースを Web に戻します。破棄後は拒否します。
markForCheck()
markForCheck() => void
ソースの再確認を予約します。呼び出しはまとめられ、変更のないスナップショットは送信しません。破棄後やランタイムがない場合は何もしません。
getStatus()
getStatus() => NativeUIStatus
現在の Web・ネイティブ投影状態を返します。
戻り値: NativeUIStatus
suspend()
suspend() => Promise<NativeUISuspension>
返されたリースを再開するまで、投影中のコントロールを Web に戻します。
戻り値: Promise<NativeUISuspension>
destroy()
destroy() => Promise<void>
同期を停止し、Web コントロールを復元してネイティブリソースを解放します。
インターフェース
NativeUIStatus
| プロパティ | 型 |
|---|---|
state |
'native' \| 'stopped' \| 'web' |
projected |
number |
updates |
number |
reason |
string |
NativeUISuspension
| メソッド | シグネチャー | 説明 |
|---|---|---|
| resume | () => Promise<void> | この中断を解放します。有効な中断をすべて解放するとネイティブ投影を再開します。 |
</docgen-api>