SwiftUI 中 UITextField 的默认值

Default Value for UITextField in SwiftUI

我已经尝试在我的项目中实现 Currency TextField,这是我在这个网站上找到的 - https://benoitpasquier.com/currency-textfield-in-swiftui

它几乎按预期工作,但有一个主要问题:传递的值未显示在 TextField 中。 (例如,Binding = 1000 在 TextField 中仍显示为 $0.00)

代码如下:

import Foundation
import SwiftUI
import UIKit

class CurrencyUITextField: UITextField {
    @Binding private var value: Int
    private let formatter: NumberFormatterProtocol

    init(formatter: NumberFormatterProtocol, value: Binding<Int>) {
        self.formatter = formatter
        self._value = value
        super.init(frame: .zero)
        setupViews()
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: superview)
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        addTarget(self, action: #selector(resetSelection), for: .allTouchEvents)
        keyboardType = .numberPad
        textAlignment = .right
        sendActions(for: .editingChanged)
    }

    override func removeFromSuperview() {
        Log.info("Removed CurrencyTextField from View")
    }

    override func deleteBackward() {
        text = textValue.digits.dropLast().string
        sendActions(for: .editingChanged)
    }

    private func setupViews() {
        tintColor = .clear
        font = .systemFont(ofSize: 40, weight: .regular)
    }

    @objc private func editingChanged() {
        text = currency(from: decimal)
        resetSelection()
        updateValue()
    }

    @objc private func resetSelection() {
        selectedTextRange = textRange(from: endOfDocument, to: endOfDocument)
    }

    private func updateValue() {
        DispatchQueue.main.async { [weak self] in
            self?.value = self?.intValue ?? 0
        }
    }

    private var textValue: String {
        return text ?? ""
    }

    private var decimal: Decimal {
        return textValue.decimal / pow(10, formatter.maximumFractionDigits)
    }

    private var intValue: Int {
        return NSDecimalNumber(decimal: decimal * 100).intValue
    }

    private func currency(from decimal: Decimal) -> String {
        return formatter.string(for: decimal) ?? ""
    }
}

extension StringProtocol where Self: RangeReplaceableCollection {
    var digits: Self { filter(\.isWholeNumber) }
}

extension String {
    var decimal: Decimal { Decimal(string: digits) ?? 0 }
}

extension LosslessStringConvertible {
    var string: String { .init(self) }
}
import SwiftUI
import UIKit

struct CurrencyTextField: View {
    @Binding var value: Int
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 15)
                .foregroundColor(.quaternary)
                .frame(maxHeight: 80)
            CurrencyTextField_(numberFormatter: NumberFormatter.currencyFormatter, value: $value)
                .padding(.horizontal)
        }
        .frame(maxHeight: 80)
    }
}

struct CurrencyTextField_: UIViewRepresentable {
    typealias UIViewType = CurrencyUITextField

    let numberFormatter: NumberFormatterProtocol
    let currencyField: CurrencyUITextField

    init(numberFormatter: NumberFormatterProtocol, value: Binding<Int>) {
        self.numberFormatter = numberFormatter
        currencyField = CurrencyUITextField(formatter: numberFormatter, value: value)
    }

    func makeUIView(context: Context) -> CurrencyUITextField {
        return currencyField
    }

    func updateUIView(_ uiView: CurrencyUITextField, context: Context) {}
}

struct CurrencyTextField_Previews: PreviewProvider {
    static var previews: some View {
        CurrencyTextField(value: .constant(1025))
    }
}

此视图可以初始化为 amount = 0,或者作为 'Edit' 视图,注入金额值(例如 1000,之前由相同的 CurrencyTextField 创建)

struct CreateTransactionView: View {
    @State var amount = 0

    var body: some View {
            VStack(alignment: .leading, spacing: 15) {
                CurrencyTextField(value: $amount)
            }
    }
}

可能导致此问题的原因是什么? PS。我对 UIKit 几乎没有经验。

updateUIView 尚未实施。 makeUIView 没有正确完成。

您可以通过更改仅适用于 iOS 15+ 的格式在 TextField 中使用货币。

@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension FormatStyle {
    public static func currency<Value>(code: String) -> Self where Self == FloatingPointFormatStyle<Value>.Currency, Value : BinaryFloatingPoint
}
struct ContentView: View {
    @State private var myMoney: Double? = 300.0
    var body: some View {
        TextField(
            "Currency (USD)",
            value: $myMoney,
            format: .currency(code: "USD")
        )
    }
}

或使用Locale

struct ContentView: View {
    private let locale = Locale.current
    @State private var myMoney: Double? = 1000.0
    var body: some View {
        TextField(
            "Currency (\(locale.currencyCode ?? "USD")",
            value: $myMoney,
            format: .currency(code: locale.currencyCode ?? "USD")
        )
    }
}