🙌

Ionic/Angularでハーフモーダルを実装する

3 min read

この記事はIonic Framework / Capacitor Advent Calendar 2020の記事です。


iOSで時々見かけていた「ハーフモーダル」ですが、最近ではAirPodsの確認画面であったり、購入確認のUIであったりよく見かけるようになりました。

※ スクリーンキャプチャ攝る時に指紋認識してジェムパックAを購入してしまったのは笑い話

元々モーダルはPUSH遷移と異なり、以前のビューと非連続的な処理をする時に利用するものですが、全面のモーダルは以前のビューが見えなくなることに対して、ハーフモーダルは以前のビューが「見えてる状態での作業の中断」を明示することができます。それでは、これをIonic/Angularで実装してみましょう。

一番シンプルなハーフモーダル

まず、 half-modal のためのCSSを用意します。 global.scss などグローバルに適用されるSCSSに記述してください。

.half-modal {
  align-items: flex-end;

  .modal-wrapper {
    height: 400px !important;
  }
  
  ion-header ion-toolbar:first-of-type {
    padding-top: 0;
  }
}

ion-appdisplay: flex ですので、その直下に入るハーフモーダルは align-items: flex-end; で下寄せを指定します。そして、 wrapper に400pxを用意します。 ion-header ion-toolbar:first-of-type を指定しているのは、Cordova/Capacitorで利用してる時に、iOSでは自動的に ion-header ion-toolbarpadding-top が変更されるのを防ぐためです。

これで、Modalを立ち上げる時にこのClassを割り当てればOKです。ハーフモーダルはスワイプでも閉じれた方がいいので、 swipeToClose も有効にします。

const modal = await this.modalCtrl.create({
  component: ModalPage,
  cssClass: ['half-modal'],
  swipeToClose: true,
});
await modal.present();

簡単ですね。

全面モーダルの上にハーフモーダルをだす

ただ、往々にしてハーフモーダルは全面モーダルの上に表示します。全モーダルを重ねて作業を中断させないためであり、ユーザに多くのビューを提示して混乱させないための配慮でもあります。ただ、上記のハーフモーダルの出現方法だと、ハーフモーダルの背景にバックドロップが表示されない問題があります。

これはIonicではModalは2枚以上だした場合、1枚目の上にくるために半透明のバックドロップが複数重なって(opacityが重なって)画面が黒くなることを防止しているためです。

ハーフモーダルでは2枚目であってもバックドロップを表示するようにCSSで指定します。

  .half-modal {
    align-items: flex-end;

    .modal-wrapper {
      height: 400px !important;
    }

    ion-header ion-toolbar:first-of-type {
      padding-top: 0;
    }
  
+   ion-backdrop {
+     --backdrop-opacity: var(--ion-backdrop-opacity, 0.4);
+   }
  }

そうすると、ハーフモーダルの後ろにもバックドロップが表示されます。便利ですね。

キーボード出現時にハーフモーダルを全面モーダルにする

モバイルデバイスでは、キーボード出現時はキーボードで画面が1/3近くを占めてしまうため、ハーフモーダルは邪魔です。もちろん、キーボードとハーフモーダルを組み合わせないUI設計をすればいいのですが、設計上組み合わせるのが必要な場合はキーボードと一緒にせり上がるようにしましょう。

まず、 .half-modal が高さが変わったらアニメーションで変化を表示するようにします。そしてModalの高さを一時的に100%にして、 ion-header ion-toolbarpadding-top も初期値に戻しましょう。

  .half-modal {
    align-items: flex-end;

    .modal-wrapper {
 +    transition: height 420ms;
      height: 400px !important;
    }

    ion-header ion-toolbar:first-of-type {
      padding-top: 0;
    }
  
    ion-backdrop {
      --backdrop-opacity: var(--ion-backdrop-opacity, 0.4);
    }
    
+   &.half-modal-keyboard {
+     .modal-wrapper {
+       height: 100% !important;
+     }
+
+     ion-header ion-toolbar:first-of-type {
+       padding-top: var(--ion-safe-area-top, 0);
+     }
    }
  }

これでキーボード出現時には、 .half-modal-keyboard を付与、キーボードが閉じる時には .half-modal-keyboard を削除すれば、キーボードにあわせて、ハーフモーダルと全面モーダルを切り替えることができるようになります。

こんな感じになります。

簡単ですね。それではまた。