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

SwiftUI中如何复用同一个列表视图适配多数据源并返回选中数据到对应父视图

SwiftUI 通用复用列表选择视图改造方案

核心改造思路

  • 把原来固定绑定CompanyData的视图改为泛型视图,支持任意遵守Identifiable协议的数据类型传入
  • 移除固定的companyName绑定,改为通用选中回调,直接返回选中的完整模型数据
  • 支持自定义列表行视图、自定义导航栏标题,适配不同业务场景的展示需求
  • 兼容原有业务逻辑,无需修改现有数据结构即可直接适配使用

改造后完整代码

import SwiftUI
import Combine

// 泛型通用选择列表视图,支持任意遵守Identifiable的数据类型
struct CommonSelectionView<T: Identifiable, Content: View>: View {
    @Environment(\.presentationMode) var presentationMode
    // 外部传入的数据源
    let dataList: [T]
    // 外部传入的导航栏标题
    let navTitle: String
    // 外部自定义列表行的构建闭包
    let rowContent: (T) -> Content
    // 选中条目后的回调,直接返回选中的完整模型数据
    let onSelect: (T) -> Void
    
    var body: some View {
        List(dataList) { data in
            Button(action: {
                onSelect(data)
                presentationMode.wrappedValue.dismiss()
            }) {
                rowContent(data)
            }
        }
        .navigationBarTitle(navTitle)
    }
}

// 预览示例
struct CommonSelectionView_Previews: PreviewProvider {
    // 模拟测试数据结构
    struct TestItem: Identifiable {
        let id = UUID()
        let name: String
    }
    
    static var previews: some View {
        NavigationStack {
            CommonSelectionView(
                dataList: [TestItem(name: "测试公司1"), TestItem(name: "测试公司2")],
                navTitle: "测试选择"
            ) { item in
                Text(item.name)
            } onSelect: { selectedItem in
                print("选中了\(selectedItem.name)")
            }
        }
    }
}

提示:如果需要适配iOS15及以下版本,将调用处的NavigationStack替换为NavigationView即可。

使用示例

1. 原有公司选择场景适配

// 父视图调用示例
struct CompanySelectParentView: View {
    @State private var showCompanySelector = false
    @State private var selectedCompanyName = ""
    // 你的公司数据源,可根据业务替换
    let companyData = [CompanyData]()
    
    var body: some View {
        VStack {
            Text("已选公司:\(selectedCompanyName)")
            Button("选择公司") {
                showCompanySelector = true
            }
        }
        .sheet(isPresented: $showCompanySelector) {
            NavigationStack {
                // 传入对应参数即可复用通用选择视图
                CommonSelectionView(
                    dataList: companyData,
                    navTitle: "Companies"
                ) { company in
                    Text(company.name ?? "")
                } onSelect: { selectedCompany in
                    selectedCompanyName = selectedCompany.name ?? ""
                }
            }
        }
    }
}

2. 其他数据类型使用示例(比如用户选择)

// 任意业务数据结构只要遵守Identifiable协议即可使用
struct User: Identifiable {
    let id = UUID()
    let userName: String
    let phone: String
}

// 父视图调用
struct UserSelectParentView: View {
    @State private var showUserSelector = false
    @State private var selectedUser: User?
    let userList = [
        User(userName: "张三", phone: "13xxxxxxxxx"),
        User(userName: "李四", phone: "13xxxxxxxxx")
    ]
    
    var body: some View {
        VStack {
            Text("已选用户:\(selectedUser?.userName ?? "未选择")")
            Button("选择联系人") {
                showUserSelector = true
            }
        }
        .sheet(isPresented: $showUserSelector) {
            NavigationStack {
                CommonSelectionView(
                    dataList: userList,
                    navTitle: "选择联系人"
                ) { user in
                    // 可完全自定义行视图样式
                    VStack(alignment: .leading) {
                        Text(user.userName)
                        Text(user.phone)
                            .font(.caption)
                            .foregroundColor(.gray)
                    }
                } onSelect: { selected in
                    selectedUser = selected
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者venkat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 11:39:03