使用元素和选择参数为 SwiftUI 选取器视图创建包装器

Create wrapper for SwiftUI Picker View with elements and selection parameters

提问人:Bartłomiej Semańczyk 提问时间:3/23/2023 最后编辑:Bartłomiej Semańczyk 更新时间:3/24/2023 访问量:137

问:

这是我的代码:

import SwiftUI

struct VPickerView<T: Hashable>: 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) { // Cannot find '$selection' in scope
                    ForEach(elements, id: \.self) {
                        Text(String($0))
                            .font(.title)
                            .foregroundColor($0 == selection as! T ? .blue : .red)
                    }
                }.onChange(of: selection) { _ in
                    print("changed")
                }
                .labelsHidden()
                .pickerStyle(.wheel)
                .border(.black, width: 5)
                .frame(width: 55)
            }
        }
    }
}

但是我收到一个错误,我不知道为什么。Cannot find '$selection' in scope

我想如何使用它?

private let hours: [Int]
@State private var selectedHour: Int = 0

var body: some View {
    VPickerView(elements: hours, selection: $selectedHour)
}

条件:

  • 所选元素应为蓝色,否则为红色。
  • 元素类型可能是 Int、Double、String、Int64
iOS SwiftUI swiftUI-picker

评论

0赞 lorem ipsum 3/23/2023
这回答了你的问题吗?如何在SwiftUI中初始化Binding : Bool变量?
0赞 Bartłomiej Semańczyk 3/24/2023
@loremipsum 不,它不一样,因为有定义的类型,这里我们有泛型类型。这种差异是这里的关键。
0赞 lorem ipsum 3/24/2023
问题是缺少包装器,如果您像该问题一样正常添加它并初始化它将起作用。要使其现在工作,只需删除它已经是您不需要它,但您将遇到 UI 更新问题,您需要self._selection = selection$Binding@Binding

答:

1赞 MarkusMichael Oh 3/23/2023 #1

请记住,SwiftUI 的 Binding 属性允许我们声明一个值实际上来自其他地方,并且应该在共享该属性的人和共享该属性的人之间共享。并且,共享者和共享者 (https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-binding-property-wrapper) 都可以修改绑定属性。

话虽如此,“private let selection: Binding”必须更改为“@Binding var selection: T”,因为 Binding 属性应该同时是 VARIABLE 和 SSHAREABLE(不是私有的)。

此外,由于 Binding 属性 (@Binding) 包装 Binding 实例,因此必须通过执行以下操作来访问其中的内容并对其进行初始化。

init(elements: [T], selection: Binding<T>) {
    self.elements = elements
    self._selection = selection
}

“_selection”的下栏允许我们到达属性内部并设置绑定属性。

一旦完成这些,编译器仍然不允许你构建提供的代码,因为<T:Hashable>不足以让 Swift 知道 $0(第一个参数)可以转换为 String。

若要解决此问题,可以考虑添加另一个协议一致性,例如 CustomStringConvertible。

struct VPickerView<T: Hashable & CustomStringConvertible>: View {
    ...codes
}

所以完整的代码可能是这样的:

struct VPickerView<T: Hashable & CustomStringConvertible>: View {
    private let elements: [T]
    @Binding private var selection: 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) { // Cannot find '$selection' in scope
                    ForEach(elements, id: \.self) {
                        Text($0.description)
                            .font(.title)
                            .foregroundColor($0 == selection ? .blue : .red)
                    }
                }.onChange(of: selection) { _ in
                    print("changed")
                }
                .labelsHidden()
                .pickerStyle(.wheel)
                .border(.black, width: 5)
                .frame(width: 55)
            }
        }
    }
}

评论

0赞 Bartłomiej Semańczyk 3/24/2023
谢谢你的回答。它有帮助。我还有一个与此相关的问题,但这是另一个问题的主题。