0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Swift モーダル画面が閉じたことを検知する方法

Last updated at Posted at 2023-03-05

iOS13から特定のスタイルでモーダル遷移をすると画面を閉じた際、 遷移元のライフサイクルメソッドが発火されない仕様になったのを今更知知りました。
画面を閉じた際、遷移元のviewWillAppearで画面表示時に毎回ある処理をさせたかったのですが、モーダルを閉じた際の検知で代用することにしました。

閉じた際の検知はUIAdaptivePresentationControllerDelegateのpresentationControllerDidDismissメソッドを使って特定できるみたいです。

中身としては以下のように画面遷移する際にpresentationControllerのdelegateを自身にセットします。

// 遷移元コード全体
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    // ボタンを押したら遷移する処理
    @IBAction func button(_ sender: Any) {
        transitionToSecondVC()
     }
    
    private func transitionToSecondVC() {
        guard let vc = UIStoryboard(name: "SecondVC", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return}
        
        vc.modalPresentationStyle = .overFullScreen

        // delegateを自身に委任
        vc.presentationController?.delegate = self
        self.present(vc, animated: true)
    }
}

extension ViewController: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        print("VC didDismiss")
    }
}

ただこれだけ書けば遷移先でdismissしたら発火するわけでも無いみたいで、さらに遷移先でdismissする時に親のpresentationControllerDidDismissメソッドを呼び出す必要があるらしいみたいです。

// 遷移先コード全体
class SecondVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    // 閉じるボタンで画面を閉じる処理 
    @IBAction func closeButton(_ sender: Any) {

        // dismiss前にpresentationControllerDidDismiss(_:)を呼び出す
        if let presentationController = presentationController {
            presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
        }
        self.dismiss(animated: true)
    }
}

こうすることで.overFullScreenで表示したSecondVCがdismissした時に、遷移元のViewControllerの print(“VC didDismiss”)が出力されるようになりました。

またモーダル画面先でナビゲーションコントローラーを使用する場合は下記のように実装します。

   private func transitionToSecondVC() {
        guard let vc = UIStoryboard(name: "SecondVC", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return}
        
        let nav = UINavigationController(rootViewController: vc)
        nav.modalPresentationStyle = .overFullScreen

        // navigationControllerのpresentationController delegateを自身に委任
        nav.presentationController?.delegate = self

        self.present(nav, animated: true)
    }

そして遷移先で閉じるときはnavigationControllerのpresentationControllerを引数に入れてメソッドを呼び出します。

   if let presentationController = self.navigationController?.presentationController {
       presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
   }

とりあえずこうすれば画面を閉じた時の検知ができるので、発火されないViewWillAppearの代わりとして使用できそうです。
これが最適かは分からないですが、とりあえず現状これ以外のいい方法は分からなかったです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?