2021年9月28日火曜日

【SwiftUI App】WindowGroup の RootView を切り替える方法

 

iOS14 から採用されている SwiftUI App ライフサイクルでは以下のように WindowGroup の中にある View(ここでは ContentView)がアプリケーションの RootView になっています。

@main
struct SampleApp: App {    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

今回はこの RootView を切り替える方法について一例として紹介したいと思います。

 

WindowGroup の RootView を切り替える方法

@StateObject

今回のポイントは @StateObject 修飾子です。

以前より、@State 修飾子と言うものはありました。@State は、Int・String・Bool といった値型の変数の状態をViewと連携させるものでしたが、@StateObjectオブジェクト型(class型)の変数を扱う場合に使用します。

以下のサンプルでは、この @StateObject として宣言したオブジェクトが持つ enum を元に RootView を分岐する例を示します。

RootView 切り替え実装例

AppState シングルトンクラス

class AppState: ObservableObject {
    
    static let shared = AppState()
    private init() {}
    
    enum RootViews {
        case splash
        case main
    }
    @Published private(set) var rootView: RootViews = .splash
    
    func changeRootView(rootView: RootViews) {
        self.rootView = rootView
    }
}

ObservableObject プロトコルに準拠した AppState と言う名前のシングルトンクラスを作成します(SwiftUI らしさを考えると EnvironmentObject で表現しても良いかもしれません)。

enum でスプラッシュ画面(splash)とメイン画面(main)の列挙子を定義しました。この値で WindowGroup の RootView を切り替えます。

SplashView と MainView

struct SplashView: View {
    var body: some View {
        Text("Splash View")
            .foregroundColor(.blue)
            .onAppear() {
                DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                    AppState.shared.changeRootView(rootView: .main)
                }
            }
    }
}

struct MainView: View {
    var body: some View {
        Text("Main View")
            .foregroundColor(.red)
    }
}

最初は、前者の SplashView が表示されています。そして表示から 2.0 秒後に AppStatechangeRootView で RootView に MainView 指定しています。

@StateObject と WindowGroup での分岐

@main
struct SampleApp: App {
    
    @StateObject private var appState = AppState.shared
    
    var body: some Scene {
        WindowGroup {
            switch appState.rootView {
            case .splash:
                SplashView()
            case .main:
                MainView()
            }
        }
    }
}

AppState.shared インスタンスを @StateObjectappState に紐づけ、WindowGroup ブロック内の switch で RootView を分岐させています。

@StateObject が付加されていなかったり、誤って @State にしてしまっていたりすると動作しませんので注意してください。

 

元ネタ https://www.yururiwork.net/archives/1188

 

 

0 件のコメント:

コメントを投稿