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

SwiftUI Picker封装报错:Cannot find '$selection' in scope 解决

SwiftUI泛型Picker组件VPickerView错误修复与实现

错误原因分析

报错“Cannot find '$selection' in scope”的核心原因:

  • 你定义的selection参数本身就是Binding<T>类型,$符号仅用于从@State、@Binding等属性包装器生成Binding实例,这里直接使用selection即可,无需添加$前缀。

其他问题修正

除了上述错误,代码中还有几处需要调整以满足需求:

  1. 文本转换严谨性:直接用String($0)虽能处理指定类型,但让泛型T遵守CustomStringConvertible协议,可确保所有支持类型都能安全转换为文本。
  2. 选中状态判断:selection是Binding类型,需通过wrappedValue获取当前选中值,无需多余的强制类型转换。
  3. 值变更监听:onChange的监听参数需要是值类型,应传入selection.wrappedValue而非Binding实例。

修正后的完整代码

import SwiftUI

// 添加CustomStringConvertible约束,确保类型可转为文本显示
struct VPickerView<T: Hashable & CustomStringConvertible>: View {
    private let elements: [T]
    private let selection: Binding<T>
    
    init(elements: [T], selection: Binding<T>) {
        self.elements = elements
        self.selection = selection
    }
    
    var body: some View {
        HStack(spacing: 5) {
            ZStack {
                Color.green
                    .frame(width: 45, height: 30)
                    .cornerRadius(15)
                Picker("", selection: selection) { // 直接使用已有的Binding类型参数
                    ForEach(elements, id: \.self) { element in
                        Text(element.description)
                            .font(.title)
                            // 通过wrappedValue获取选中值,判断颜色
                            .foregroundColor(element == selection.wrappedValue ? .blue : .red)
                    }
                }
                .onChange(of: selection.wrappedValue) { _ in
                    print("changed")
                }
                .labelsHidden()
                .pickerStyle(.wheel)
                .border(.black, width: 5)
                .frame(width: 55)
            }
        }
    }
}

需求满足说明

  • 选中状态颜色:通过element == selection.wrappedValue判断是否为选中项,选中时显示蓝色,未选中显示红色。
  • 支持类型:Int、Double、String、Int64均默认遵守Hashable和CustomStringConvertible协议,可直接传入组件使用。

使用示例

struct ContentView: View {
    private let hours: [Int] = Array(0...23)
    @State private var selectedHour: Int = 0
    
    // 其他支持类型的使用示例
    private let weights: [Double] = Array(stride(from: 0.0, through: 100.0, by: 0.5))
    @State private var selectedWeight: Double = 0.0
    
    private let names: [String] = ["Alice", "Bob", "Charlie"]
    @State private var selectedName: String = "Alice"
    
    private let largeNumbers: [Int64] = [10000000000, 20000000000, 30000000000]
    @State private var selectedLargeNum: Int64 = 10000000000
    
    var body: some View {
        VStack(spacing: 20) {
            VPickerView(elements: hours, selection: $selectedHour)
            VPickerView(elements: weights, selection: $selectedWeight)
            VPickerView(elements: names, selection: $selectedName)
            VPickerView(elements: largeNumbers, selection: $selectedLargeNum)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 10:30:22