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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:27:04