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

SwiftUI WheelPicker滚动时无法更新绑定变量的问题求助

解决SwiftUI WheelPicker滚动时实时更新绑定值的问题

默认的SwiftUI WheelPicker确实只会在滚动停止后才触发绑定值更新,要实现苹果时钟App那样滚动过程中实时同步的效果,需要自己封装原生的UIPickerView并监听滚动中的选中事件,具体方案如下:

自定义实时更新的WheelPicker

通过UIViewRepresentable封装UIPickerView,利用其代理方法在滚动过程中实时更新绑定值:

struct WheelPicker: UIViewRepresentable {
    typealias UIViewType = UIPickerView
    
    @Binding var selectedValue: Int
    let values: [Int]
    
    func makeUIView(context: Context) -> UIPickerView {
        let picker = UIPickerView()
        picker.dataSource = context.coordinator
        picker.delegate = context.coordinator
        // 初始化选中行
        picker.selectRow(values.firstIndex(of: selectedValue) ?? 0, inComponent: 0, animated: false)
        // 保持系统滚轮样式
        picker.selectionIndicatorStyle = .white
        return picker
    }
    
    func updateUIView(_ uiView: UIPickerView, context: Context) {
        // 外部绑定值变化时同步更新Picker选中状态
        let targetIndex = values.firstIndex(of: selectedValue) ?? 0
        if uiView.selectedRow(inComponent: 0) != targetIndex {
            uiView.selectRow(targetIndex, inComponent: 0, animated: true)
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        let parent: WheelPicker
        
        init(_ parent: WheelPicker) {
            self.parent = parent
        }
        
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            1
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            parent.values.count
        }
        
        // 自定义滚轮文字样式,匹配原SwiftUI样式
        func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
            let label = (view as? UILabel) ?? UILabel()
            label.text = "\(parent.values[row]) minutes"
            label.font = UIFont.preferredFont(forTextStyle: .body).withSize(UIFont.systemFontSize)
            label.textColor = .white
            label.textAlignment = .center
            return label
        }
        
        // 滚动过程中实时更新绑定值
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            parent.selectedValue = parent.values[row]
        }
    }
}

在ContentView中使用自定义Picker

替换原来的系统Picker,绑定minutes变量即可实现滚动时实时更新:

struct ContentView: View {
    @State private var minutes: Int = 1
    private let minuteRange = Array(1..<120)

    var body: some View {
        VStack {
            // 使用自定义滚轮Picker
            WheelPicker(selectedValue: $minutes, values: minuteRange)
                .frame(height: 200) // 设置合适的滚轮高度
        }
        .padding()
        .background(Color.black) // 方便查看白色文字
    }
}

核心原理

系统SwiftUI Picker为了优化性能,默认只在滚动结束后触发绑定更新;而原生UIPickerView的didSelectRow代理方法会在滚动过程中每一次选中行切换时触发,通过封装这个原生组件,就能实现像时钟App那样的实时同步效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:20:41