swiftui中uitextfield的默认值

发布于 2025-01-23 10:37:28 字数 4299 浏览 0 评论 0原文

我已经尝试将货币Textfield实施到我的项目上,我在此网站上找到了它 - https:/https:// /benoitpasquier.com/currency-textfield-in-swiftui

它几乎可以按预期工作,但是有一个主要问题:传递的价值并未出现在Textfield中。 (例如,绑定= 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))
    }
}

此视图可以以量= 0初始化,也可以以“编辑”视图(例如1000,以前由同一crurnertextfield创建)的“编辑”视图(例如1000) )

struct CreateTransactionView: View {
    @State var amount = 0

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

可能导致这个问题是什么? PS。我对Uikit几乎没有经验。

I've tried to implement Currency TextField to my project, which I found on this website - https://benoitpasquier.com/currency-textfield-in-swiftui.

It almost does work as expected, but with one major issue: passed value is not showing up in TextField. (eg. Binding = 1000 is still presented as $0.00 in TextField)

Code below:

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))
    }
}

This view can be initialised with amount = 0, or as an 'Edit' view, with injected amount value (eg. 1000, previously created by the same CurrencyTextField)

struct CreateTransactionView: View {
    @State var amount = 0

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

What could be possibly causing this issue?
PS. I have little to no experience with UIKit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

極樂鬼 2025-01-30 10:37:28

您可以通过更改仅适用于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")
        )
    }
}

You can use currency in TextField by changing the format which is only available for iOS 15+.

@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")
        )
    }
}

or using 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")
        )
    }
}
层林尽染 2025-01-30 10:37:28

UpdateUiview尚未实现。 makeuiview无法正确完成。

MakeUiview应在本地启动Uiview并将其返回。

updateUIView hasn't been implemented. And makeUIView isn't done correctly.

makeUIView should init the UIView locally and return it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文