SwiftUI MVVM架构下ForEach列表Cell点赞按钮切换状态实现方案问询
SwiftUI MVVM架构下列表Cell点赞功能实现方案
核心逻辑说明
- 所有Town数据的唯一数据源存储在
TownsViewModel的@Published属性towns中,点赞状态修改必须操作该数据源才能触发列表自动刷新 - Cell视图通过闭包回调的方式将点赞事件传递到父级ViewModel执行修改,避免跨层级状态共享混乱问题
各文件修改代码
1. TownsViewModel.swift 新增点赞切换方法
class TownsViewModel : ObservableObject { @Published var towns = [Town]() func getTowns() { for town in townsArray { towns.append(town) } } // 新增:根据town id切换点赞状态 func toggleLike(for townId: String) { guard let index = towns.firstIndex(where: { $0.id == townId }) else { return } towns[index].liked.toggle() } }
2. TownsListView.swift 传递数据与回调闭包到Cell
struct TownsListView: View { @StateObject private var viewModel = TownsViewModel() var body: some View { ScrollView() { ForEach(viewModel.towns) { town in // 传入当前town实例、点赞回调方法 TownView( town: town, onLike: { viewModel.toggleLike(for: town.id) } ) .padding(.bottom) .frame(width: 300, height: 40, alignment: .center) .background(Color.yellow) } } .onAppear { viewModel.getTowns() } } }
3. TownView 相关修改,两种方案按需选择
方案A:移除冗余的TownViewModel(更轻量,适合Cell无复杂业务的场景)
struct TownView : View { // 接收传入的town数据 let town: Town // 接收点赞事件回调 let onLike: () -> Void var body : some View { HStack { Text(town.name) Spacer() Button(action: onLike) { // 根据liked状态切换图标样式 Image(systemName: town.liked ? "heart.fill" : "heart") .foregroundColor(town.liked ? .red : .gray) } } } }
方案B:保留TownViewModel(适合Cell有独立复杂业务的场景)
首先修改TownViewModel.swift:
class TownViewModel : ObservableObject { let townId: String private let onLike: () -> Void init(townId: String, onLike: @escaping () -> Void) { self.townId = townId self.onLike = onLike } func setLike() { onLike() } }
再修改TownView.swift:
struct TownView : View { let town: Town @StateObject var viewModel: TownViewModel // 初始化时传入所需参数 init(town: Town, onLike: @escaping () -> Void) { self.town = town _viewModel = StateObject(wrappedValue: TownViewModel(townId: town.id, onLike: onLike)) } var body : some View { HStack { Text(town.name) Spacer() Button(action: { viewModel.setLike() }) { Image(systemName: town.liked ? "heart.fill" : "heart") .foregroundColor(town.liked ? .red : .gray) } } } }
内容的提问来源于stack exchange,提问作者brain
相关产品推荐
相关产品推荐

