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

如何在SwiftUI的ForEach中为NavigationLink配置自定义目标视图

如何在SwiftUI的ForEach中为NavigationLink配置自定义目标视图

我明白你的需求:你有一个动态的设置项列表,每个可跳转的项需要打开对应的专属视图(比如点击Account跳AccountView,点击Notification跳NotificationView),而且这些视图都是独立的,没法用一个通用的DetailView来复用。目前你的代码里NavigationLink的destination传的是item.title(字符串),这显然不对——SwiftUI要求这里传的是一个View类型,所以咱们得给每个Setting项建立和目标视图的关联。

下面给你两种实用的解决方案,你可以根据自己的偏好选择:


方案一:给Setting添加视图构造闭包(灵活直接)

这种方式最直观,直接给Setting结构体加一个闭包属性,用来返回对应的目标视图:

1. 修改Setting模型

添加一个返回任意View的闭包属性:

struct Setting: Identifiable, Hashable {
    var id: UUID = UUID()
    var title: String
    var isToggle: Bool
    var chevronPhoto: Bool
    var shouldShowNavigationLink: Bool
    // 新增:闭包,返回目标视图
    var destination: () -> any View
}

2. 更新ViewModel的设置项

初始化每个Setting时,直接指定对应的视图:

class SettingsViewModel: ObservableObject {
    @Published var isToggle = false // 注意:如果每个开关需要独立状态,这里要调整,比如给Setting加isOn绑定
    
    let accountValue: [Setting] = [
        Setting(title:"Account", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true) {
            AccountView() // 绑定Account视图
        },
        Setting(title:"Profile", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true) {
            ProfileView() // 绑定Profile视图
        },
        Setting(title:"Notification", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true) {
            NotificationView() // 绑定Notification视图
        }
    ]
}

3. 修改NavigationLink的Destination

在SettingSectionView里,把原来的字符串替换成闭包返回的视图,用AnyView擦除类型:

NavigationLink(destination: {
    AnyView(item.destination())
}, label: {
    // 你的ZStack布局代码不变
})

方案二:用枚举映射视图(类型更安全)

如果希望代码更规整、类型更安全,可以用枚举来定义所有可能的目标视图,再和Setting关联:

1. 定义目标视图枚举

用枚举列出所有设置项对应的视图,并用@ViewBuilder返回具体视图:

enum SettingDestination: Hashable {
    case account
    case profile
    case notification
    
    @ViewBuilder
    var targetView: some View {
        switch self {
        case .account:
            AccountView()
        case .profile:
            ProfileView()
        case .notification:
            NotificationView()
        }
    }
}

2. 修改Setting模型

添加一个可选的枚举属性,用来标记该设置项的目标视图:

struct Setting: Identifiable, Hashable {
    var id: UUID = UUID()
    var title: String
    var isToggle: Bool
    var chevronPhoto: Bool
    var shouldShowNavigationLink: Bool
    // 新增:可选的目标枚举,不需要跳转的项设为nil
    var destination: SettingDestination?
}

3. 更新ViewModel的设置项

给每个可跳转的项指定对应的枚举值:

class SettingsViewModel: ObservableObject {
    @Published var isToggle = false
    
    let accountValue: [Setting] = [
        Setting(title:"Account", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true, destination: .account),
        Setting(title:"Profile", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true, destination: .profile),
        Setting(title:"Notification", isToggle: false, chevronPhoto: true, shouldShowNavigationLink:true, destination: .notification),
        // 不需要跳转的项,destination设为nil
        Setting(title:"Dark Mode", isToggle: true, chevronPhoto: false, shouldShowNavigationLink:false, destination: nil)
    ]
}

4. 修改NavigationLink的Destination

在SettingSectionView里,根据枚举值获取对应的视图:

NavigationLink(destination: {
    item.destination?.targetView ?? EmptyView()
}, label: {
    // 你的ZStack布局代码不变
})

额外提示

你当前代码里的Toggle绑定的是$settingsVM.isToggle,这意味着所有开关都会共用同一个状态。如果每个设置项需要独立的开关状态,建议给Setting结构体添加一个isOn: Binding<Bool>属性,或者在ViewModel里为每个开关单独创建@Published变量。

备注:内容来源于stack exchange,提问作者Luka Šalipur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 14:14:53