问题描述
现在,我有以下几点:
private var currencyFormatter: NumberFormatter = {
let f = NumberFormatter()
// allow no currency symbol, extra digits, etc
f.isLenient = true
f.numberStyle = .currency
return f
}()
TextField("Total", value: $totalInput, formatter: currencyFormatter)
.font(.largeTitle)
.padding()
.background(Color.white)
.foregroundColor(Color.black)
.multilineTextAlignment(.center)
我希望文本字段以 $0.00 作为占位符开始,但是当用户开始输入时,前两个输入将以美分填充...因此 5055 将逐渐显示为:
I want the textfield to start with $0.00 as a placeholder, but when the user starts entering, the first two inputs will be populated in the cents... so 5055 would progressively show as:
第 1 步(用户点击 5 次):0.05 美元
第 2 步(用户点击 0):$0.50
第 3 步(用户点击 5):$5.05
第 4 步(用户点击 5):50.55 美元
如果金额超过 999 美元,则会插入逗号.
If the amount becomes greater than $999, then commas would be inserted.
如何做到这一点?现在我的 totalInput 类型是 Double?.
How would one accomplish this? Right now my totalInput is type Double?.
推荐答案
要创建允许用户从右到左键入金额的货币字段,您需要一个可观察对象(绑定管理器)、一个货币数字格式化程序和每次使用 onChange 方法观察值的变化:
To create a currency field that allow the user to type an amount from right to left you would need an observable object (binding manager), a currency number formatter and observe every time the value changes using onChange method:
import SwiftUI
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct ContentView: View {
@ObservedObject private var bindingManager = TextBindingManager(amount: 0)
var decimal: Decimal { bindingManager.text.decimal / pow(10, Formatter.currency.maximumFractionDigits) }
var maximum: Decimal = 999_999_999.99
@State private var lastValue: String = ""
@State private var locale: Locale = .current {
didSet { Formatter.currency.locale = locale }
}
var body: some View {
VStack(alignment: .leading) {
TextField(bindingManager.text, text: $bindingManager.text)
.keyboardType(.numberPad)
.multilineTextAlignment(.trailing) // this will keep the text aligned to the right
.onChange(of: bindingManager.text) { string in
if string.decimal > maximum {
self.bindingManager.text = lastValue
} else {
self.bindingManager.text = decimal.currency
lastValue = self.bindingManager.text
}
return
}
}
.padding()
.onAppear {
Formatter.currency.locale = locale
}
}
}
class TextBindingManager: ObservableObject {
@Published var text: String = ""
var amount: Decimal = .zero
init(amount: Decimal) {
self.amount = amount
self.text = Formatter.currency.string(for: amount) ?? "$0.00"
}
}
fileprivate extension Formatter {
static let currency: NumberFormatter = .init(numberStyle: .currency)
}
extension NumberFormatter {
convenience init(numberStyle: Style) {
self.init()
self.numberStyle = numberStyle
}
}
extension StringProtocol where Self: RangeReplaceableCollection {
var digits: Self { filter (\.isWholeNumber) }
}
extension String {
var decimal: Decimal { Decimal(string: digits) ?? 0 }
}
extension Decimal {
var currency: String { Formatter.currency.string(for: self) ?? "" }
}
这是相当于我为 UIKit 实现的自定义 CurrencyField 的 SwiftUI.
This is the SwiftUI equivalent to the custom CurrencyField I have implemented for UIKit.
这篇关于如何使用户仅在 SwiftUI 文本字段中输入数字货币,同时保留 $ 和 .?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!