如何使用户仅在 SwiftUI 文本字段中输入数字货币,同时保留 $ 和 .? [英] How to make it so that user enters currency only with numbers in SwiftUI textfield, while preserving the $ and the .?

查看:36
本文介绍了如何使用户仅在 SwiftUI 文本字段中输入数字货币,同时保留 $ 和 .?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在,我有以下几点:

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 美元

Step 1 (user hits 5): $0.05
Step 2 (user hits 0): $0.50
Step 3 (user hits 5): $5.05
Step 4 (user hits 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 文本字段中输入数字货币,同时保留 $ 和 .?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆