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")
)
}
}
我已经尝试在我的项目中实现 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")
)
}
}