SwiftUI中如何展示列表中多选项目的合并详情视图
SwiftUI 列表多选及批量详情加载实现方案
核心思路
通过ObservableObject搭配@Published统一管理选中项状态,借助ViewModel封装API调用逻辑,最终实现批量展示所有选中项的详情数据。
1. 创建ViewModel管理状态与API逻辑
import SwiftUI // 定义详情数据模型(根据实际API返回结构调整) struct FruitDetail: Codable, Identifiable { var id: String { name } let name: String let nutrition: String let origin: String // 其他需要展示的字段... } class FruitViewModel: ObservableObject { @Published var items: [String] = ["Apples", "Oranges", "Bananas", "Pears", "Mangos","grapefruit","Kela","Angur","Papita","tarbooj"] @Published var selectedFruits: [String] = [] @Published var fruitDetails: [FruitDetail] = [] @Published var isLoading: Bool = false @Published var errorMessage: String? // 批量加载选中水果的详情API func loadSelectedDetails() async { isLoading = true errorMessage = nil fruitDetails.removeAll() var fetchedDetails: [FruitDetail] = [] for fruit in selectedFruits { do { // 替换为你的详情API地址 guard let url = URL(string: "https://your-api.com/fruits/\(fruit.lowercased())") else { throw NSError(domain: "无效URL", code: -1, userInfo: nil) } let (data, _) = try await URLSession.shared.data(from: url) let detail = try JSONDecoder().decode(FruitDetail.self, from: data) fetchedDetails.append(detail) } catch { errorMessage = "加载\(fruit)详情失败: \(error.localizedDescription)" } } DispatchQueue.main.async { self.fruitDetails = fetchedDetails self.isLoading = false } } // 切换水果选中状态 func toggleSelection(for fruit: String) { if selectedFruits.contains(fruit) { selectedFruits.removeAll { $0 == fruit } } else { selectedFruits.append(fruit) } } }
2. 修改主视图绑定ViewModel
struct HomeActivity: View { @StateObject private var viewModel = FruitViewModel() @State private var showDetailView = false var body: some View { NavigationView { VStack { Button("查看选中项详情") { showDetailView = true } .disabled(viewModel.selectedFruits.isEmpty) .padding() List { ForEach(viewModel.items, id: \.self) { fruit in DetailView( title: fruit, isSelected: viewModel.selectedFruits.contains(fruit) ) { viewModel.toggleSelection(for: fruit) } } } } .navigationTitle("水果列表") .sheet(isPresented: $showDetailView) { SelectedItemsDetailView(viewModel: viewModel) } .alert(item: $viewModel.errorMessage) { message in Alert(title: Text("加载失败"), message: Text(message), dismissButton: .default(Text("确定"))) } } } } // 保留原选中项视图,简化逻辑 struct DetailView: View { var title: String var isSelected: Bool var action: () -> Void var body: some View { Button(action: action) { HStack { Text(title) if isSelected { Spacer() Image(systemName: "checkmark") } } } } }
3. 创建批量详情展示视图
struct SelectedItemsDetailView: View { @ObservedObject var viewModel: FruitViewModel var body: some View { NavigationView { VStack { if viewModel.isLoading { ProgressView("加载中...") } else if viewModel.fruitDetails.isEmpty { Text("暂无详情数据") .foregroundColor(.gray) } else { List(viewModel.fruitDetails) { detail in VStack(alignment: .leading, spacing: 8) { Text(detail.name) .font(.headline) Text("营养信息: \(detail.nutrition)") Text("产地: \(detail.origin)") } .padding(.vertical, 4) } } } .navigationTitle("选中水果详情") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("刷新") { Task { await viewModel.loadSelectedDetails() } } } } .onAppear { Task { await viewModel.loadSelectedDetails() } } } } }
关键说明
- 状态同步:用
@StateObject和@Published实现选中项的响应式更新,确保所有视图实时同步选中状态。 - API批量调用:通过
async/await实现异步请求,遍历选中项逐个调用详情API,完成后统一更新UI。 - 错误处理:通过
@Published的errorMessage传递错误信息,用系统弹窗展示给用户。 - 视图交互:主视图通过
sheet弹出详情页,详情页在加载时显示进度条,支持手动刷新数据。
内容的提问来源于stack exchange,提问作者tintin
相关产品推荐
相关产品推荐

