如何使用户在SwiftUI文本字段中仅使用数字输入货币,同时保留美元和。?

如何使用户在SwiftUI文本字段中仅使用数字输入货币,同时保留美元和。?,swift,swiftui,textfield,currency,Swift,Swiftui,Textfield,Currency,现在,我有以下几点: private var currencyFormatter: NumberFormatter = { let f = NumberFormatter() // allow no currency symbol, extra digits, etc f.isLenient = true f.numberStyle = .currency return f }() 我希望文本字段以$0.00开头作为占位符,但当用户开始输入时,前两个输入

现在,我有以下几点:

private var currencyFormatter: NumberFormatter = {
    let f = NumberFormatter()
    // allow no currency symbol, extra digits, etc
    f.isLenient = true
    f.numberStyle = .currency
    return f
}()
我希望文本字段以$0.00开头作为占位符,但当用户开始输入时,前两个输入将填充在美分中。。。因此,5055将逐步显示为:

步骤1用户点击5:$0.05 步骤2用户点击0:$0.50 步骤3用户点击5:$5.05 步骤4用户点击5:$50.55

如果金额超过999美元,则将插入逗号


如何做到这一点?现在我的totalInput类型为Double?

要创建允许用户从右到左键入金额的货币字段,您需要一个可观察的对象绑定管理器、货币编号格式化程序,并使用onChange方法在每次值更改时进行观察:

import SwiftUI

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这是相当于我为UIKit实现的自定义的SwiftUI。

要创建允许用户从右到左键入金额的货币字段,您需要一个可观察的对象绑定管理器、货币编号格式化程序,并使用onChange方法在每次值更改时进行观察:

import SwiftUI

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这是SwiftUI,相当于我为UIKit实现的自定义界面。

我创建了一个围绕UITextfield的组件

你可以在这里查看

这是演示


我已经创建了一个围绕UITextfield的组件

你可以在这里查看

这是演示


这不符合OP的要求。OP希望从右向左输入值。它也不显示$0.00。这不符合OP的要求。OP希望从右向左输入值。它也不显示$0.00。为什么在扩展中使用fileprivate?这是要放在它自己的视图中,而不是放在ContentView中,以便在应用程序中使用吗?这是为了避免在代码的其他地方更改格式化程序设置。只要保留货币设置,您可以将其删除以在应用程序中的其他地方使用。@Rolando如果您仍然需要使用十进制类型而不是双精度类型的帮助,请告诉我在表示此类内容时使用十进制与双精度是否更好?使用Int/Double的其他变量进行计算的转换看起来很混乱。是。Double它不如Decimal精确。查看这篇文章。确保始终使用字符串初始值设定项,否则在强制转换为十进制之前,您的值将被解释为Double。正如我在你的另一篇文章中所评论的,如果你需要强制你的十进制数为Double或Int,你需要先将它转换为NSDecimalNumber。我会一直使用十进制。为什么在扩展中使用fileprivate?这是要放在它自己的视图中,而不是放在ContentView中,以便在应用程序中使用吗?这是为了避免在代码的其他地方更改格式化程序设置。只要保留货币设置,您可以将其删除以在应用程序中的其他地方使用。@Rolando如果您仍然需要使用十进制类型而不是双精度类型的帮助,请告诉我在表示此类内容时使用十进制与双精度是否更好?使用Int/Double的其他变量进行计算的转换看起来很混乱。是。Double它不如Decimal精确。查看这篇文章。确保始终使用字符串初始值设定项,否则在强制转换为十进制之前,您的值将被解释为Double。正如我在你的另一篇文章中所评论的,如果你需要强制你的十进制数为Double或Int,你需要先将它转换为NSDecimalNumber。我会一直使用十进制。
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) ?? "" }
}