Help us understand the problem. What is going on with this article?

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

概要

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

手順は

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

IMG_0911.PNG

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

https://developer.apple.com/documentation/uikit/view_controllers/disabling_pulling_down_a_sheet

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

https://developer.apple.com/videos/play/wwdc2019/224

詳しく

最小限のコードで

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を返せば閉じるのをブロックできる、というような説明をしています。

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229890-presentationcontrollershoulddism?language=objc

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

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

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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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