SwiftUI中模型变更时如何更新子视图?MVVM场景问题排查
SwiftUI MVVM嵌套Model状态切换与视图更新问题修复
问题根源
- 颜色未与状态绑定:
Seats类中color仅在初始化时设置,后续isSelected状态变化时没有同步更新颜色,导致点击按钮后颜色不变化。 - 未监听单个实例变化:子视图使用
@Binding数组,但未监听单个Seats实例的@Published属性变化,状态更新后视图无法自动刷新。 - ForEach标识不当:使用数组
offset作为ForEach的id,易引发视图复用问题,且无法精准触发单个元素的更新。
修复方案
1. 调整Seats类,绑定状态与颜色
给isSelected添加didSet监听,状态变化时自动更新color,确保颜色与选中状态实时同步:
class Seats : ObservableObject, Codable, Identifiable { let id = UUID() let seatType : String? let status : Int? @Published var color: Color = Color.gray @Published var isSelected = false { didSet { color = isSelected ? .blue : .gray } } func toggleIsSelectedStatus() { isSelected = !isSelected } enum CodingKeys: String, CodingKey { case seatType = "seatType" case status = "status" } required init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) seatType = try values.decodeIfPresent(String.self, forKey: .seatType) status = try values.decodeIfPresent(Int.self, forKey: .status) color = isSelected ? .blue : .gray } }
2. 修改子视图,实现局部更新
使用@ObservedObject监听单个Seats实例,ForEach直接使用实例自身的id作为标识,确保仅更新点击的按钮:
struct GateSectionView: View { @Binding var data:[Seats] private let adaptiveColumns = [ GridItem(.adaptive(minimum: 30)) ] var body: some View { VStack(spacing: 0) { LazyVGrid(columns: adaptiveColumns) { ForEach(data) { seat in @ObservedObject var observedSeat = seat Button { observedSeat.toggleIsSelectedStatus() } label: { Text("\(data.firstIndex(of: seat)! + 1)") .font(.system(size: 10, weight: .bold)) .frame(width: 25, height: 25) .foregroundColor(.white) } .background(observedSeat.color) .cornerRadius(3) } }.padding(10) Spacer() } .cornerRadius(12) .frame(width: 780) } }
3. 清理父视图冗余代码
移除未使用的@State var setas = [Seats](),简化结构:
struct SeatSelectionView: View { @StateObject var seatLayoutViewModel = SeatLayoutViewModel() var body: some View { ZStack { Color.white ScrollView(.horizontal) { VStack(spacing: -5) { HStack { GateSectionView(data: $seatLayoutViewModel.totalSeats) .frame(width: 780) } .padding(.top, 10) .padding(.horizontal, 5) } .padding(.horizontal, 8) .padding(.bottom) } } .onAppear { seatLayoutViewModel.getSeatMasterData() } } }
修复效果
点击按钮时,对应Seats实例的isSelected状态切换,color自动更新,@ObservedObject触发单个按钮视图刷新,实现仅更新点击的按钮,符合局部更新的需求。
内容的提问来源于stack exchange,提问作者Arnav Singh
相关产品推荐
相关产品推荐

