35
17

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.

新たに追加されたUIViewController viewIsAppearingの使い方

Last updated at Posted at 2023-10-06

概要

新たに追加されたUIViewControllerのviewIsAppearing(_:)について説明します。

viewIsAppearingは、画面の初期表示時にUIをアップデートしたい時に使うものになっています。

viewIsAppearingが使える環境について

viewIsAppearingはiOS 13から使えるAPIになります。ですが、開発環境がXcode 15ではないと使えないという、iOSとしては珍しい、後方互換がサポートされている新規APIになります。

viewIsAppearingの特徴

Choosing the appropriate callbackの図を見れば一目瞭然なのですが、viewIsAppearingの動作タイミングは、viewWillAppear(_:)viewDidAppear(_:)の間のタイミングで行われます。
そして、viewWillLayoutSubviews()viewDidLayoutSubviews()など他のレイアウトメソッドと違い、viewIsAppearingは一回の表示につき一回しか行われません。

viewIsAppearingは、viewDidAppearと違ってトランジション前に行われるので、画面表示前にビューに対して何か処理を行うのに有効です。
画面表示前という意味だとviewWillAppearも同じですが、リンク先の図や表を見る限りviewWillAppear実行時はレイアウト前の状態なのに対し、viewIsAppearingではすでにレイアウトが行われViewのサイズやTraitなどが確定した状態になっているので、画面サイズやSize Classesによって処理を変更したりできます。

viewIsAppearingの使用例

例えば、画面幅によって縦方向と横方向が切り替わるUIStackViewを考えてみます。
UIStackViewにはUILabelが複数あり、一列に収まるようであれば一列表示、そうでなければ縦に並べるようなUIStackViewです。
サンプルにUIViewControllerを作成しました。

class StackViewController: UIViewController {
    private var stackView: UIStackView!
    
    override func loadView() {
        // ここの長さによって縦方向、横方向が切り替わる
        let l1 = UILabel()
        l1.text = "123456789"
        let l2 = UILabel()
        l2.text = "bbbbbbbbbb"
        let l3 = UILabel()
        l3.text = "ccccccccccccccccccc"
        
        let stackView = UIStackView(arrangedSubviews: [l1,l2,l3])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .horizontal
        stackView.distribution = .fill
        
        let view = UIView()
        view.backgroundColor = .systemBackground
        view.addSubview(stackView)
        
        NSLayoutConstraint.activate([stackView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor),
                                     stackView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor),
                                     stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)])
        
        self.stackView = stackView
        self.view = view
    }

    /// StackViewの内容によって、axisを切り替える
    private func setupStackView() {
        let desiredStackViewWidth = stackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
        let availableWidth = view.readableContentGuide.layoutFrame.width

        if desiredStackViewWidth > availableWidth {
            stackView.axis = .vertical
        } else {
            stackView.axis = .horizontal
        }
    }
}

このコードを元に、いろんなイベントで確かめてみます。

viewWillAppear

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        setupStackView()
    }

処理結果

viewWillAppearだと横一列にUILabelが並ぶ

このコードを実装しても、viewWillAppearではまだ画面幅が正確に確定していない状態なので表示は一列に収まると判断されて横並びで省略されてしまい、期待した結果となりません。

viewDidAppear

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setupStackView()
    }

viewDidAppearだと遷移中は横一列にUILabelが並んでしまう

viewDidAppearで実装した場合、最終的には縦方向にUILabelが並びますが、トランジション中は一列に横並びすることになります。

viewIsAppearing

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
        setupStackView()
    }

Simulator Screenshot - iPhone 15 Pro - 2023-10-06 at 09.30.47.png

viewIsAppearingで実装した場合、viewWillAppearやviewDidAppearで起こった問題は起こらず、正しく縦に並びます。

UILabelの文字数を減らした場合は横にレイアウトされています。

Simulator Screenshot - iPhone 15 Pro - 2023-10-06 at 09.31.08.png

参考

35
17
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
35
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?