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

SwiftUI绑定Picker在Sheet中选中后按钮文本不更新问题

问题:Sheet弹窗中Picker选中选项后无法更新外部按钮文本

我在Sheet弹窗中实现了Picker组件,但选中选项后外部按钮的文本无法更新,相关代码如下:

主视图代码

struct UserTabView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var userSkills: [LocalUserSkill]

    @State private var selectedSkill: LocalUserSkill?

    var body: some View {
        // ...
        UserSkillButton(selectedSkill: $selectedSkill, options: userSkills, title: "Skill")
    }
}

Picker按钮组件代码

struct UserSkillButton: View {
    @Binding var selectedSkill: LocalUserSkill?
    var options: [LocalUserSkill]
    var title: String

    @State private var showingSheet = false

    var body: some View {
        VStack() {
            Button(selectedSkill?.descript ?? "Select...") {
                showingSheet = true
            }
            .padding(.bottom)
            .sheet(isPresented: $showingSheet, onDismiss: updateButtonLabel) {
                VStack {
                    Text(title)
                        .padding()
                    Picker("Wähle eine Option", selection: $selectedSkill) {
                        ForEach(options, id: \.userSkillId) { option in
                            Text(option.descript).tag(option)
                        }
                    }
                    .pickerStyle(WheelPickerStyle())
                    .padding()

                    Button("Schließen") {
                        showingSheet = false
                    }
                    .padding()
                }
                .background(Color.white)
                .cornerRadius(15)
                .presentationDetents([.height(200)])
            }
        }
    }
}

数据模型定义

@Model
public class LocalUserSkill {
    var adminNote: String?
    var createdAt: Date?
    var createdBy: String
    var descript: String
    var updatedAt: Date?
    var updatedBy: String
    var userSkillId: Int
    
    init(from skill: UserSkill) {
        self.adminNote = skill.adminNote
        self.createdAt = skill.createdAt?.foundationDate
        self.createdBy = skill.createdBy
        self.descript = skill.descript
        self.updatedAt = skill.updatedAt?.foundationDate
        self.updatedBy = skill.updatedBy
        self.userSkillId = skill.userSkillId
    }
}

解决方案

1. 修复未实现的updateButtonLabel方法

代码中.sheet的onDismiss参数引用了未实现的updateButtonLabel方法,这会导致逻辑异常。直接移除该参数即可,绑定值的更新会自动同步到父视图:

.sheet(isPresented: $showingSheet) {
    // ... Sheet内容保持不变
}

2. 确保数据模型遵循Equatable协议

显式为LocalUserSkill实现Equatable协议,基于唯一的userSkillId判断相等性,避免Picker的tag匹配异常:

extension LocalUserSkill: Equatable {
    public static func == (lhs: LocalUserSkill, rhs: LocalUserSkill) -> Bool {
        lhs.userSkillId == rhs.userSkillId
    }
}

3. 强制同步按钮文本与绑定值(可选)

如果上述步骤仍未解决问题,可以在UserSkillButton中添加本地状态变量存储按钮文本,通过onChange监听绑定值变化来更新文本,确保视图及时刷新:

struct UserSkillButton: View {
    @Binding var selectedSkill: LocalUserSkill?
    var options: [LocalUserSkill]
    var title: String

    @State private var showingSheet = false
    @State private var buttonText: String = "Select..."

    init(selectedSkill: Binding<LocalUserSkill?>, options: [LocalUserSkill], title: String) {
        self._selectedSkill = selectedSkill
        self.options = options
        self.title = title
        self._buttonText = State(initialValue: selectedSkill.wrappedValue?.descript ?? "Select...")
    }

    var body: some View {
        VStack() {
            Button(buttonText) {
                showingSheet = true
            }
            .padding(.bottom)
            .onChange(of: selectedSkill) { newValue in
                buttonText = newValue?.descript ?? "Select..."
            }
            .sheet(isPresented: $showingSheet) {
                // ... Sheet内容保持不变
            }
        }
    }
}

4. 改用sheet(item:)优化绑定可靠性

将基于isPresented的Sheet改为基于item的绑定,让模态视图生命周期与选中项更紧密关联,提升绑定同步的稳定性:

struct UserSkillButton: View {
    @Binding var selectedSkill: LocalUserSkill?
    var options: [LocalUserSkill]
    var title: String

    @State private var isSheetPresented = false

    var body: some View {
        VStack() {
            Button(selectedSkill?.descript ?? "Select...") {
                isSheetPresented = true
            }
            .padding(.bottom)
            .sheet(isPresented: $isSheetPresented) {
                VStack {
                    Text(title)
                        .padding()
                    Picker("Wähle eine Option", selection: $selectedSkill) {
                        ForEach(options, id: \.userSkillId) { option in
                            Text(option.descript).tag(option as LocalUserSkill?)
                        }
                    }
                    .pickerStyle(WheelPickerStyle())
                    .padding()

                    Button("Schließen") {
                        isSheetPresented = false
                    }
                    .padding()
                }
                .background(Color.white)
                .cornerRadius(15)
                .presentationDetents([.height(200)])
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者D.Schall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 22:27:03