LoginSignup
47
31

More than 3 years have passed since last update.

iOS13からのUIModalPresentationStyle.pageSheetでユーザにプルダウンで閉じられないようにする方法

Last updated at Posted at 2019-10-09

概要

iOS13からのページシート(ハーフモーダルちっくな標準のモーダル)で、ユーザにプルダウンで閉じられたくない場合にどのようにするかというのを書いておきます。

手順は

  • iOS13からのUIViewControllerのフラグvar isModalInPresentation: Boolをtrueにすると閉じられないようにできる
  • var viewWillLayoutSubviews: Boolがtrueの際にUIAdaptivePresentationControllerDelegateのメソッドでユーザが閉じようとした際に自前のアラートを表示するようにできる

IMG_0911.PNG

これについてはAppleのサンプルコードが下記にあります

このコードはWWDC19のセッション「Modernizing Your UI for iOS 13」で解説されていました

詳しく

最小限のコードで

class EditViewController: UIViewController, UIAdaptivePresentationControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // フラグをtureにするとpull down時に下記delegateが動作する
        isModalInPresentation = true
    }

    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {

        // UIAlertControllerで閉じてよいか自前で表示する
        ...
    }

その他

やりたいことはそこで終わりですが、気になったことがあるので書いておきます

サンプルコードにある編集中を示すやり方

サンプルコードではUITextViewが変更されたかどうか、つまりisModalInPresentation: BoolをtrueにしたりfalseにするタイミングをUIViewControllerviewWillLayoutSubviews()でやっています。

これはもし複数UITextViewがある場合に無駄がないようにしているのだと思います。

    override func viewWillLayoutSubviews() {

        // Ensure textView.text is up to date
        textView.text = editedText

        // If our model has unsaved changes, prevent pull to dismiss and enable the save button
        let hasChanges = self.hasChanges
        isModalInPresentation = hasChanges
        saveButton.isEnabled = hasChanges
    }

これ、テキストが変更されたらeditedTextプロパティを書き換えてそこのdidSetでsetNeedsLayoutさせてViewのレイアウトを更新するタイミングを要求しています。それが次。

    var editedText = "" {
        didSet {
            viewIfLoaded?.setNeedsLayout()
        }
    }

こうすることで流れとして次のようにテキストの値を変えてフラグを変更しています。

  • ユーザがUITextViewでテキストを変更
    • UITextViewDelegateでプロパティeditedTextを書き換え
    • editedTextが書き換わるとviewWillLayoutSubviews()が動作
      • textView.text = editedTextでUITextViewを上書き)
      • isModalInPresentationをtrueかfalseに

気付きとしてはviewIfLoaded?.setNeedsLayout()なんて短い時間に何回読んでもそれらがまとめて実行されるので、もし複数UITextViewがある場合もフラグisModalInPresentationの変更が無駄に書き換わらないのでしょう。hasChangesフラグはUITextViewごとに必要になるでしょうが、その結果のフラグはまとめて切り替えているというやり方な気がします。

  • hasChanges: ガンガン変わっていい
  • isModalInPresentation: ガンガン変わらないようにviewWillLayoutSubviewsのタイミングで書き換えられている

presentationControllerShouldDismiss

サンプルコードにはありませんが、

「Modernizing Your UI for iOS 13」ではvar viewWillLayoutSubviews: Boolがfalseでも、デリゲートoptional func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool
でfalseを返せば閉じるのをブロックできる、というような説明をしています。

スクリーンショット 2019-10-11 11.03.40.png

つまり、編集中ではないのでvar isModalInPresentation: Boolをfalseにするとしても、アニメーション中などはoptional func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Boolでfalseにしておくことで、プルダウンさせてもアラートを表示させられるよ、ということでしょう...。

47
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
31