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

SwiftUI可选Picker遇EnvironmentObject变更失选及新增Meter选中问题

问题解决方案

核心修改思路

针对你遇到的两个问题,核心是用唯一ID跟踪选中状态(避免实例匹配失效),并监听数据变化自动更新选中项。


修改后的完整代码

struct Meters: View {
    
    @EnvironmentObject var dataStore: DataStore
    
    var property: Property
    @State private var selectedMeterId: UUID? // 改用ID跟踪选中项,需确保Meter有UUID类型的id属性
    @State private var addMeter = false
    
    // 通过ID匹配当前选中的Meter
    private var selectedMeter: Property.Meter? {
        property.meters.first { $0.id == selectedMeterId }
    }
    
    var body: some View {
        NavigationStack {
            Group {
                if property.meters.isEmpty {
                    BlankView(text: "meter")
                } else {
                    if let selectedMeter = selectedMeter {
                        ReadingsList(property: property, meter: selectedMeter)
                    }
                }
            }
            .navigationBarTitleDisplayMode(.inline)
            .navigationTitle(property.name)
            .toolbar {
                ToolbarItem {
                    Button("+ Meter") {
                        addMeter = true
                    }
                }
                ToolbarItem(placement: .status) {
                    // 同步修改MetersList,接收ID绑定
                    MetersList(property: property, selectedMeterId: $selectedMeterId)
                }
            }
            .sheet(isPresented: $addMeter) {
                AddMeter(property: property)
            }
            // 初始化默认选中第一个Meter
            .onAppear {
                if selectedMeterId == nil && !property.meters.isEmpty {
                    selectedMeterId = property.meters.first?.id
                }
            }
            // 监听Meter列表变化,新增后自动选中最新项
            .onChange(of: property.meters) { newMeters in
                if !newMeters.isEmpty {
                    selectedMeterId = newMeters.last?.id
                }
            }
        }
    }
}

// 配套修改MetersList视图
struct MetersList: View {
    var property: Property
    @Binding var selectedMeterId: UUID?
    
    var body: some View {
        Picker("Select Meter", selection: $selectedMeterId) {
            ForEach(property.meters) { meter in
                Text(meter.name).tag(meter.id as UUID?)
            }
        }
        .pickerStyle(.menu)
    }
}

问题针对性解决说明

1. 新增Meter后自动选中

  • 通过.onChange(of: property.meters)监听Meter列表的变化,当新增Meter后,直接将selectedMeterId设为列表最后一项的ID(即刚添加的Meter),实现自动选中。
  • 保留.onAppear逻辑,确保进入视图时若已有Meter,默认选中第一个。

2. 避免Picker视图刷新后失选

  • 原问题根源:直接存储Property.Meter实例时,EnvironmentObject更新会导致property.meters中的Meter实例被重新创建(尤其当Meter是struct类型时),旧选中实例与新列表实例不匹配,导致Picker失选。
  • 解决方式:改用Meter的唯一标识(如id)跟踪选中状态,即使Meter实例被重建,只要ID不变,就能通过ID匹配到对应项,保持选中状态。
  • 需同步修改MetersList,让Picker的选中值绑定到selectedMeterId,并将每个选项的tag设为对应Meter的ID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:44:51