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 秒後に AppState の changeRootView で 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 インスタンスを @StateObject の appState に紐づけ、WindowGroup ブロック内の switch で RootView を分岐させています。
@StateObject が付加されていなかったり、誤って @State にしてしまっていたりすると動作しませんので注意してください。
元ネタ https://www.yururiwork.net/archives/1188
0 件のコメント:
コメントを投稿