69
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

公式「ハーフモーダル」がやってきた! #wwdc21

iOS 15からハーフモーダルっぽい表示が標準APIを使ってできるようになりました。この記事ではその「ハーフモーダル」について紹介しているCustomize and resize sheets in UIKitという動画を紹介してみます。

概要

従来の場合

今までモーダルは全画面表示でした(スクショは.pageSheetの場合)。

iOS 15 〜

iOS 15では「medium」モードにすると画面の半分だけを覆うシートが作成できるようになりました。

スクリーンショット 2021-06-28 18.55.24.png

landscapeやiPadのときの表示はこのようになります。

スクリーンショット 2021-06-28 9.27.33.png
スクリーンショット 2021-06-28 9.27.53.png
スクリーンショット 2021-06-28 9.27.00.png

detentsとは

まず最初にdetentsというものを理解する必要があります。detentsとはシートが自然に止まる高さのことを表し、.medium().large()が用意されています。

スクリーンショット 2021-06-28 11.25.32.png
スクリーンショット 2021-06-28 11.25.47.png

コードで書くとこんなかんじです。この指定により、シートの覆い具合を調整することができます。まずviewControllersheetPresentationControllerを取得します。このシートに対しdetentsを設定してあげると、サイズの指定ができます。デフォルトでは.large()のみが設定された状態だと解釈されます。設定とその結果の対応は以下の通りです。

  • .large()のみ
    • フルサイズのシートが表示される(リサイズ不可)
  • .medium().large()の両方
    • mediumとlargeでリサイズ可能なシートが表示される
  • .medium()のみ
    • ハーフサイズのシートが表示される(リサイズ不可)

スクリーンショット 2021-06-28 11.37.34.png

detentsを用いた実装例

従来の場合

例えば写真ピッカーは次のような実装をして表示していたと思います。
スクリーンショット 2021-06-29 7.51.47.png
スクリーンショット 2021-06-28 11.50.19.png

detentsでサイズ指定

iOS 15から、例えば以下のコード、表示ができます。

スクリーンショット 2021-06-29 7.55.16.png

  • PHPickerViewControllersheetPresentationControllerを取得してdetents.medium().large()を設定
    • リサイズ可能なシートを表示する
  • ピッカーのdidFinishPickingデリゲートからdismiss行を削除
    • 写真を選択し終わってもシートが完全に閉じないようにする

これにより、シートを半分にした状態で写真を選択することも、ドラッグしてフルサイズにしたシートから写真を選択することもできます。

スクリーンショット 2021-06-28 12.00.02.png

スクロール制御

ただし、このままだと上にスクロールした時にシート自体もスクロールしてフルサイズになってしまい、「スクロールすると、シートは半分のままで、ピッカー内の写真一覧だけがスクロールされる」状態にならなくなってしまいます。バーをドラッグした時にシートのサイズが変わるようにするにはprefersScrollingExpandsWhenScrolledToEdgefalseにする必要があります。
スクリーンショット 2021-06-28 13.02.15.png

選択時のサイズ指定

次の改善ポイントは写真選択時のアクションです。.large()の状態で写真を選択しても、選択された写真が表示されるエリアは見れないので、ちゃんと写真が選択されたのかその場でわかりません。そこで、写真が選択された時はシートが.medium()の大きさになるよう変更してみます。デリゲートメソッド内でselectedDetentIdentifier.mediumに設定します。
スクリーンショット 2021-06-28 13.14.26.png

リサイズ時にアニメーションをつける

写真選択時に.large()から.medium()に変更できたのはいいものの、このままだとアニメーションがないのでいきなりサイズが変わってしまいます。次のようにanimateChangesブロックで囲むと、自然なアニメーションをつけることができます。
スクリーンショット 2021-06-28 13.21.48.png

dimmingを消す

スクリーンショット 2021-06-29 8.11.04.png
選択された写真エリアが薄暗いので、dimmingを解除してみます。smallestUndimmedDetentIdentifierの設定をいじることで解除が可能です。このプロパティはデフォルトnilで、すべてのdetentsでdimmingがかかっています。dimmingを解除したい場合はdimmingさせたくない最小のdetentsを設定します。
スクリーンショット 2021-06-28 13.32.16.png

このプロパティは視覚的に「薄暗さ」を取り除くだけではなく、シート外のコンテンツにアクセスできるような「ノンモーダル状態」を作ることができます。ので、.medium()の時に写真選択エリアに触れて操作することもできます。

キーボードとの併用

スクリーンショット 2021-06-29 8.11.29.png
.medium()の時にキーボードを表示すると、自動で.large()サイズになります。キーボードが消えると.medium()サイズに戻ります。

視覚的なカスタマイズ

detentsを操作する以外のところでもいろいろできます。

landscape時のシートサイズ

今までは全画面表示にするしかありませんでした。
スクリーンショット 2021-06-28 14.26.54.png

iOS 15からは、シートの下端だけが画面の縁についている状態で表示できるprefersEdgeAttachedInCompactHeightが追加されました。これをtrueにするとSafe Areaと同じ幅のシートを表示できます。
image.png

presentedViewControllerspreferredContentSizeに沿った幅のシートにしたい場合は、widthFollowsPreferredContentSizeWhenEdgeAttachedtrueに設定します。preferredContentSizeを設定することで、幅をさらにカスタマイズすることもできます。
スクリーンショット 2021-06-28 14.35.17.png

grabberの表示非表示

prefersGrabberVisibleの設定で、grabberの表示非表示を操作することができます。
スクリーンショット 2021-06-28 15.40.42.png

シートのリサイズが可能であることがわかりづらい場合にはgrabberを表示すると役に立ちます。

シートのradius変更

シートの角丸具合を調整することもできます。
スクリーンショット 2021-06-28 17.18.04.png

iPadでポップオーバーを表示する場合

写真ピッカーをポップオーバーにするにはまずmodalPresentationStyle.popoverを設定します。次に、先程のようにsheetPresentationControllerを取得するのではなく、popoverPresentationControllerを取得します。ポップオーバーのsourceをbarButtonItemに設定し、adaptiveSheetPresentationControllerというポップオーバーの新しいプロパティを取得します。このプロパティはポップオーバーがcompactサイズのクラスに適応するシートのインスタンスを返してくれます。
スクリーンショット 2021-06-28 17.23.20.png

これで写真ボタンをタップするとポップオーバーに写真ピッカーが表示され、領域のサイズを小さくすると、.medium()サイズのシートが表示されるようになりました。
image.png
image.png

ただし、このままだと.large()状態で写真を選択した時に自動で.medium()サイズになってくれません。popoverPresentationControlleradaptiveSheetPresentationControllerを取得して先程と同じように設定する必要があります。
image.png

まとめ

  • iOS 15からハーフモーダルっぽいUIが標準APIを使って作れるようになったよ
  • ちょこちょこカスタマイズできるよ
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
69
Help us understand the problem. What are the problem?