如何在 SwiftUI 中更改焦点文本字段的值?

问题描述 投票:0回答:2

我有一个重点文本框。

@FocusState private var focusedField: Field?
TextField("0", value: $price, format: .currency(code: "USD").locale(Locale(identifier: "en_US")))
            .keyboardType(.numbersAndPunctuation)
            .multilineTextAlignment(.trailing)
            .focused($focusedField, equals: field)

还有一个按钮

Button("Tap") { price = 200 }

但是,如果文本字段获得焦点,则不能使用按钮重写文本字段中的值。文本字段需要不聚焦才能做到这一点。

当我重写代码时:

Button("Tap") {
    focusedField = nil
    price = 200
}

它会关闭键盘,但仍然不会重写文本字段中的值。只有在键盘关闭后,如果我再次点击按钮,它才会重写文本字段中的值。

我怎样才能完成这项工作?

ios swift swiftui focus textfield
2个回答
1
投票

在 SwiftUI 中,TextField 在获得焦点时不会更新其绑定。强制更新的一种方法是利用 TextField 的 onChange 事件。

首先,为之前的价格值创建一个状态:

@State private var previousPrice: String = ""

然后,将一个

onChange
事件添加到您的
TextField
以更新
previousPrice
状态:

TextField("0", value: $price, format: .currency(code: "USD").locale(Locale(identifier: "en_US")))
    .keyboardType(.numbersAndPunctuation)
    .multilineTextAlignment(.trailing)
    .focused($focusedField, equals: field)
    .onChange(of: price, perform: { value in
        previousPrice = value
    })

现在,在您的按钮操作中,将

price
值与
previousPrice
进行比较。如果它们相同,则意味着 TextField 尚未更新其绑定。因此,您可以先将
price
设置为空字符串,然后在短暂的延迟后将其设置回所需的值。

Button("Tap") {
    if price == previousPrice {
        price = ""
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            price = 200
        }
    } else {
        price = 200
    }
}

这将确保 TextField 中的值即使在获得焦点时也会更新。


0
投票

根据我的评论,您可以尝试这种替代方法, 使用

String
,如示例代码所示。

因为在

TextField
中,如果值是字符串,文本字段会不断更新此值……对于非字符串类型,它会在用户提交编辑时更新值,例如通过按 Return 键。

对我来说效果很好。就是多了几行代码,但至少有 没有等待 0.1 秒的广告。

enum Field: Hashable {
     case price
 }

struct ContentView: View {
    var body: some View {
        TestView()
    }
}

struct TestView: View {
    @State private var txt = ""
    @State private var price = 0.0
    
    @FocusState private var focusedField: Field?
    
    func asCurrency(_ str: String) -> String {
        if let value = Double(str) {
            let frmt = NumberFormatter()
            frmt.numberStyle = .currency
            frmt.maximumFractionDigits = 2
            frmt.minimumFractionDigits = 2
            frmt.locale = Locale(identifier: "en_US")
            if let str = frmt.string(for: value) {
                return str
            }
        }
        return ""
    }

    var body: some View {
        TextField(asCurrency("0"), text: Binding(
            get: { asCurrency(txt) },
            set: {
                if let d = Double($0) {
                    price = d
                    txt = $0
                }
            }))
        .keyboardType(.numbersAndPunctuation)
        .multilineTextAlignment(.trailing)
        .focused($focusedField, equals: .price)
        
        Button("Tap") {
            focusedField = nil
            price = 200.0
            txt = String(price)
        }
    }
}
 
© www.soinside.com 2019 - 2024. All rights reserved.