You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
            }
        }
    }
}

用按钮触发逻辑,再通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:53:17