SwiftUI中如何在导航时执行逻辑并创建新对象?
Tapas编辑视图导航问题解决方案
问题描述
我有一个EditTapasView用于编辑用户创建的Tapas。用户点击“New Tapas”按钮时,需跳转至该视图并传入新创建的Tapas:
- 此前用
sheet实现正常,但在EditTapasView中新增NavigationLink后,sheet内的导航无法正常工作。 - 直接使用
NavigationLink时,会在视图渲染时自动持续创建新Tapas,无需点击按钮。 - 尝试编程式导航未成功,错误地将视图赋值给
NavigationStack的path。
相关错误代码示例:
直接使用NavigationLink的错误写法
NavigationLink(destination: EditTapasView(tapas: addTapas())) { Text("New Tapas") .font(.system(size: 17)) .padding(.trailing) .padding([.top, .bottom], 10) }
错误的编程式导航写法
NavigationStack (path: $path) { Button(action: { newTapas = addTapas() path = EditTapasView(tapas: newTapas) }, label: { Text("New Tapas") .font(.system(size: 17)) .padding(.trailing) .padding([.top, .bottom], 10) }) }
解决方案
方法1:正确使用NavigationStack编程式导航
NavigationStack的path应存储数据模型而非视图,需确保Tapas遵循Hashable协议,通过navigationDestination映射数据到视图:
// 确保Tapas模型遵循Identifiable和Hashable struct Tapas: Identifiable, Hashable { let id = UUID() // 自定义属性 } struct ParentView: View { @State private var path: [Tapas] = [] private func addTapas() -> Tapas { // 实现创建新Tapas的逻辑 Tapas() } var body: some View { NavigationStack(path: $path) { Button(action: { let newTapas = addTapas() path.append(newTapas) }, label: { Text("New Tapas") .font(.system(size: 17)) .padding(.trailing) .padding([.top, .bottom], 10) }) // 绑定数据类型到目标视图 .navigationDestination(for: Tapas.self) { tapas in EditTapasView(tapas: tapas) } } } }
方法2:通过isActive绑定控制NavigationLink
用按钮触发逻辑,再通过isActive激活导航,避免视图渲染时执行创建逻辑:
struct ParentView: View { @State private var isNavigating = false @State private var newTapas: Tapas? private func addTapas() -> Tapas { Tapas() } var body: some View { NavigationStack { Button(action: { newTapas = addTapas() isNavigating = true }, label: { Text("New Tapas") .font(.system(size: 17)) .padding(.trailing) .padding([.top, .bottom], 10) }) // 隐藏NavigationLink,通过isActive控制 .background( NavigationLink( destination: EditTapasView(tapas: newTapas!), isActive: $isNavigating ) { EmptyView() } ) } } }
方法3:给NavigationLink添加点击事件
通过onTapGesture在点击时执行创建逻辑,需设置按钮样式避免事件冲突:
struct ParentView: View { @State private var newTapas: Tapas? private func addTapas() -> Tapas { Tapas() } var body: some View { NavigationStack { NavigationLink(destination: EditTapasView(tapas: newTapas!)) { Text("New Tapas") .font(.system(size: 17)) .padding(.trailing) .padding([.top, .bottom], 10) } .onTapGesture { newTapas = addTapas() } .buttonStyle(.plain) // 避免默认按钮样式的重复点击触发 } } }
错误原因说明
- 直接在
NavigationLink的destination中调用addTapas():SwiftUI会在视图首次渲染及每次刷新时执行该方法,导致自动创建大量Tapas。 - 错误的编程式导航:
NavigationStack的path需存储遵循Hashable的数据类型,而非视图实例,否则无法正确触发导航。
内容的提问来源于stack exchange,提问作者Sphere
相关产品推荐
相关产品推荐

