我遇到了一个有趣的行为(或者这可能是预期的行为,但我错了)。当我使用
@AppStorage
来将用户引导至入职或不入职时,第一个入职视图会显示两次。很难解释,这是一个gif:
单击“完成入门”后,我必须导航到 MainView,但第一个视图会以某种方式再次显示在中间。
仍然很难解释,所以这里是最基本的 SwiftUI 代码,你可以自己尝试一下:
import SwiftUI
@main
struct OnboardingApp: App {
@AppStorage("onboardingCompleted") var onboardingCompleted = false
var body: some Scene {
WindowGroup {
if !onboardingCompleted {
FirstView()
} else {
MainView()
}
}
}
}
struct FirstView: View {
var body: some View {
NavigationStack {
VStack {
Text("Welcome")
NavigationLink("Second") {
SecondView()
}
}
.onAppear {
print("First View")
}
}
}
}
struct SecondView: View {
@AppStorage("onboardingCompleted") var onboardingCompleted = false
var body: some View {
VStack {
Text("Onboarding complete")
Button("Finish the onboarding") {
onboardingCompleted = true
}
}
.onAppear {
print("Second View")
}
}
}
struct MainView: View {
@AppStorage("onboardingCompleted") var onboardingCompleted = true
var body: some View {
NavigationStack {
VStack {
Text("Hello, Main View!")
Button("Uncomplete onboarding") {
onboardingCompleted = false
}
}
.onAppear {
print("Main View")
}
}
}
}
为什么
@AppStorage
var 更改后又显示了 FirstView?
入职完成后,
onboardingCompleted
将为 true,因此您可以使用它来区分“正常”onAppear
呼叫和移动到 MainView
时发生的意外呼叫。
@AppStorage("onboardingCompleted") var onboardingCompleted = false
...
.onAppear {
if !onboardingCompleted {
print("First View")
}
}
或者,将
onAppear
移至 NavigationStack
。
有趣的是,这种行为在 macOS 上不会发生。
我的猜测(所以对此持保留态度)是 SwiftUI 使用
NavigationStack
实现 UINavigationController
,并将堆栈上的每个视图包装到自己的 UIHostingController
中,并且 onAppear
在 viewWillAppear
中被调用
。当移动到 MainView
时,由于某种原因 UINavigationController
会弹出到 root,因此 FirstView
的 onAppear
会被调用。