SwiftUI Picker封装报错:Cannot find '$selection' in scope 解决
SwiftUI泛型Picker组件VPickerView错误修复与实现
错误原因分析
报错“Cannot find '$selection' in scope”的核心原因:
- 你定义的
selection参数本身就是Binding<T>类型,$符号仅用于从@State、@Binding等属性包装器生成Binding实例,这里直接使用selection即可,无需添加$前缀。
其他问题修正
除了上述错误,代码中还有几处需要调整以满足需求:
- 文本转换严谨性:直接用
String($0)虽能处理指定类型,但让泛型T遵守CustomStringConvertible协议,可确保所有支持类型都能安全转换为文本。 - 选中状态判断:
selection是Binding类型,需通过wrappedValue获取当前选中值,无需多余的强制类型转换。 - 值变更监听:
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
相关产品推荐
相关产品推荐

