Skip to content

0x031-swiftui的TextField限制输入两位小数

使用SwiftUIIntrospect是最简单有效的方式了。

swift
...
private let tfDelegate = TfDelegate()
...

TextField("其他金额", text: $payAmountInput)
	.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18)) { tf in
		tf.delegate = self.tfDelegate
	}
	.frame(width: 100)
	.textFieldStyle(.roundedBorder)
	.keyboardType(.decimalPad)
...
private let tfDelegate = TfDelegate()
...

TextField("其他金额", text: $payAmountInput)
	.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18)) { tf in
		tf.delegate = self.tfDelegate
	}
	.frame(width: 100)
	.textFieldStyle(.roundedBorder)
	.keyboardType(.decimalPad)

代理设置:

swift
class TfDelegate: NSObject, UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard textField.keyboardType == .decimalPad, let oldText = textField.text, let r = Range(range, in: oldText) else {
            return true
        }

        let newText = oldText.replacingCharacters(in: r, with: string)
        let isNumeric = newText.isEmpty || (Double(newText) != nil)

        let formatter = NumberFormatter()
        formatter.locale = Locale.current
        let decimalPoint = formatter.decimalSeparator ?? "."
        let numberOfDots = newText.components(separatedBy: decimalPoint).count - 1

        let numberOfDecimalDigits: Int
        if let dotIndex = newText.index(of: ".") {
            numberOfDecimalDigits = newText.distance(from: dotIndex, to: newText.endIndex) - 1
        } else {
            numberOfDecimalDigits = 0
        }
        return isNumeric && numberOfDots <= 1 && numberOfDecimalDigits <= 2
    }
}
class TfDelegate: NSObject, UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard textField.keyboardType == .decimalPad, let oldText = textField.text, let r = Range(range, in: oldText) else {
            return true
        }

        let newText = oldText.replacingCharacters(in: r, with: string)
        let isNumeric = newText.isEmpty || (Double(newText) != nil)

        let formatter = NumberFormatter()
        formatter.locale = Locale.current
        let decimalPoint = formatter.decimalSeparator ?? "."
        let numberOfDots = newText.components(separatedBy: decimalPoint).count - 1

        let numberOfDecimalDigits: Int
        if let dotIndex = newText.index(of: ".") {
            numberOfDecimalDigits = newText.distance(from: dotIndex, to: newText.endIndex) - 1
        } else {
            numberOfDecimalDigits = 0
        }
        return isNumeric && numberOfDots <= 1 && numberOfDecimalDigits <= 2
    }
}