我正在编写一个类似 anki 的应用程序,带有语言练习。完成练习后,您将进入下一个单词的练习,依此类推,无限期地进行。我想使用导航在单词之间进行转换。这是我想出的一个简化示例:
struct ContentView: View {
@State private var page: Int = 0
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
VStack {
NavigationLink("Go to page \(page)", value: page)
}
.navigationDestination(for: Int.self) { currentPage in
VStack {
Text("You selected \(currentPage)")
Button("Next page") {
page += 1
path.removeLast()
path.append(page)
}
}.onAppear() {
print("View with page \(page) is appearing")
}
}
}
}
}
我使用带有推送和弹出功能的导航路径,将最上面的视图“替换”为下一个单词练习。请注意,我不想只是将视图“推入”堆栈,因为这样它将无限期地增长。我还希望通过“后退”按钮进入主菜单,而不是之前的练习。提供的代码有效,但转换到下一页时没有动画。此外,导航到下一页时不会调用“onAppear”方法。
怀疑这与视图层次结构没有改变有关,我尝试使用 .id 修饰符使 VStack 视图的 id 依赖于页面,并将不同类型的对象推送到路径中 - 这些都没有帮助。
如果有任何关于如何解决这个问题的想法,我将非常感激!
按照您的方式,没有发生导航。您不会创建新视图,您只是更新同一视图 (ContentView) 中的值。从逻辑上讲,因为没有导航,所以没有导航过渡动画。这也是
.onAppear
不触发的原因,因为根视图永远不会消失。
要实际导航,请为新页面创建一个新结构,该结构接受必要的值,例如页面和路径。然后,在
.navigationDestination
中调用它。
由于您的导航模型很简单,基于数字,因此您可以通过使用 Int 数组作为路径而不是 NavigationPath 类型来让您的生活更轻松,我相信这允许类型擦除 - 这意味着它可以容纳任何东西,而不仅仅是Int 类型。下面的代码以 Int 数组为例。
如果只需要返回根,则不需要压入和弹出来管理路径堆栈。您可以保持简单并继续推动,直到弹出所有内容以转到根视图。
尝试一下:
import SwiftUI
struct PopNavigation: View {
//State values
@State private var page: Int = 1
@State private var path: [Int] = []
//Body
var body: some View {
NavigationStack(path: $path) {
VStack {
NavigationLink("Go to page \(page)", value: page)
}
.navigationDestination(for: Int.self) { currentPage in
NavPageView(page: $page, path: $path)
}
.navigationTitle("Main")
}
}
}
struct NavPageView: View {
//Parameters
@Binding var page: Int
@Binding var path: [Int]
//Body
var body: some View {
VStack {
Text("You selected \(page)")
Button {
page += 1
path.append(page)
} label: {
Text("Next page")
}
}
.onAppear() {
print("View with page \(page) is appearing")
}
.navigationTitle("Page \(page)")
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden() //hide default back button
.toolbar {
ToolbarItem(placement: .topBarLeading) {
//Custom back button
Button {
//Back to root
path.removeLast(path.count)
} label: {
HStack {
Image(systemName: "chevron.left")
Text("Back to Main")
}
}
}
}
}
}
#Preview {
PopNavigation()
}