SwiftUI 中的@propertywrapper
@propertywrapper in SwiftUI
我创建了一个@propertyWrapper 来限制变量可以达到的数量。我在 SwiftUI 视图中尝试了它,它带有一个增加变量值的按钮并且它起作用了,变量停止在初始化程序中设置的最大数量处。但是,如果我用 Textflied 尝试它,它不起作用,如果我插入一个比一组更大的数字,什么也没有发生,它让我这样做。我该如何解决这个问题,我知道这个问题与绑定有关,但我不知道它到底是什么,这是代码:
import SwiftUI
struct ContentView: View {
@Maximum(maximum: 12) var quantity: Int
var body: some View {
NavigationView{
Form{
TextField("", value: $quantity, format: .number, prompt: Text("Pizza").foregroundColor(.red))
Button {
quantity += 1
} label: {
Text("\(quantity)")
}
}
}
}
}
@propertyWrapper
struct Maximum<T: Comparable> where T: Numeric {
@State private var number: T = 0
var max: T
var wrappedValue: T {
get { number }
nonmutating set { number = min(newValue, max) }
}
var projectedValue: Binding<T> {
Binding(
get: { wrappedValue },
set: { wrappedValue = [=10=] }
)
}
init(maximum: T){
max = maximum
}
}
extension Maximum: DynamicProperty {
}
@Asperi 关于如何创建 属性 包装器的说法完全正确。但是,这并没有解决 TextField()
的问题。问题似乎是您实际上并没有在 TextField
上使用 $quantity
,而是使用来自 $quantity.
派生的格式化程序的字符串这似乎不允许更新机制正常工作。
但是,您可以简单地通过将 @State
字符串输入 TextField
,然后更新 .onChange(of:)
中的所有内容来解决此问题。这允许您将 quantity
设置为 TextField
的 Int
值,最大值可防止 quantity
过高。然后你转身将你的字符串设置为 quantity.description
以保持一切同步。
最后一件事,我将 keyboardType
更改为 .decimalPad
以使输入更容易。
struct ContentView: View {
@Maximum(maximum: 12) var quantity: Int
@State private var qtyString = "0"
var body: some View {
NavigationView{
Form{
TextField("", text: $qtyString, prompt: Text("Pizza").foregroundColor(.red))
.onChange(of: qtyString) { newValue in
if let newInt = Int(newValue) {
quantity = newInt
qtyString = quantity.description
}
}
.keyboardType(.decimalPad)
Button {
quantity += 1
} label: {
Text("\(quantity)")
}
}
}
}
}
@propertyWrapper
struct Maximum<T: Comparable>: DynamicProperty where T: Numeric {
let number: State<T> = State(initialValue: 0)
var max: T
var wrappedValue: T {
get { number.wrappedValue }
nonmutating set { number.wrappedValue = min(newValue, max) }
}
var projectedValue: Binding<T> {
Binding(
get: { wrappedValue },
set: { wrappedValue = [=10=] }
)
}
init(maximum: T){
max = maximum
}
}
我创建了一个@propertyWrapper 来限制变量可以达到的数量。我在 SwiftUI 视图中尝试了它,它带有一个增加变量值的按钮并且它起作用了,变量停止在初始化程序中设置的最大数量处。但是,如果我用 Textflied 尝试它,它不起作用,如果我插入一个比一组更大的数字,什么也没有发生,它让我这样做。我该如何解决这个问题,我知道这个问题与绑定有关,但我不知道它到底是什么,这是代码:
import SwiftUI
struct ContentView: View {
@Maximum(maximum: 12) var quantity: Int
var body: some View {
NavigationView{
Form{
TextField("", value: $quantity, format: .number, prompt: Text("Pizza").foregroundColor(.red))
Button {
quantity += 1
} label: {
Text("\(quantity)")
}
}
}
}
}
@propertyWrapper
struct Maximum<T: Comparable> where T: Numeric {
@State private var number: T = 0
var max: T
var wrappedValue: T {
get { number }
nonmutating set { number = min(newValue, max) }
}
var projectedValue: Binding<T> {
Binding(
get: { wrappedValue },
set: { wrappedValue = [=10=] }
)
}
init(maximum: T){
max = maximum
}
}
extension Maximum: DynamicProperty {
}
@Asperi 关于如何创建 属性 包装器的说法完全正确。但是,这并没有解决 TextField()
的问题。问题似乎是您实际上并没有在 TextField
上使用 $quantity
,而是使用来自 $quantity.
派生的格式化程序的字符串这似乎不允许更新机制正常工作。
但是,您可以简单地通过将 @State
字符串输入 TextField
,然后更新 .onChange(of:)
中的所有内容来解决此问题。这允许您将 quantity
设置为 TextField
的 Int
值,最大值可防止 quantity
过高。然后你转身将你的字符串设置为 quantity.description
以保持一切同步。
最后一件事,我将 keyboardType
更改为 .decimalPad
以使输入更容易。
struct ContentView: View {
@Maximum(maximum: 12) var quantity: Int
@State private var qtyString = "0"
var body: some View {
NavigationView{
Form{
TextField("", text: $qtyString, prompt: Text("Pizza").foregroundColor(.red))
.onChange(of: qtyString) { newValue in
if let newInt = Int(newValue) {
quantity = newInt
qtyString = quantity.description
}
}
.keyboardType(.decimalPad)
Button {
quantity += 1
} label: {
Text("\(quantity)")
}
}
}
}
}
@propertyWrapper
struct Maximum<T: Comparable>: DynamicProperty where T: Numeric {
let number: State<T> = State(initialValue: 0)
var max: T
var wrappedValue: T {
get { number.wrappedValue }
nonmutating set { number.wrappedValue = min(newValue, max) }
}
var projectedValue: Binding<T> {
Binding(
get: { wrappedValue },
set: { wrappedValue = [=10=] }
)
}
init(maximum: T){
max = maximum
}
}