RxSwift替换应该更改字符的范围

时间:2018-05-28 03:07:11

标签: ios swift rx-swift

我想在Uxextfield中使用RxSwift。我的目标是在用户键盘中允许/不输入字符并从复制粘贴中删除字符,我需要处理UITextfield的委托" shouldChangeCharactersInRange"使用 RxSwift

如何使用 RxSwift 实现?

我正在使用RxSwift版本4。 情况1: 键盘输入:A123 来自RxSwift的过程:接受123(不允许使用NumberPad) 输出:123

案例2: 输入表单从联系人复制粘贴:\ U202d1111111111 \ U202c 从RxSwift处理:删除所有控制字符,接受1111111111 输出:1111111111

如果一般我们可以使用shouldChangeCharactersInRange,但如何使用RxSwift?

2 个答案:

答案 0 :(得分:4)

通常,即使您不使用Rx,也不应在shouldChangeCharactersInRange中对状态进行突变。该回调是查询而不是命令。该文本字段只是询问您是否应执行默认行为,而不是告诉您对其进行更新。您尝试实现的行为应该在editChanged操作中。

由于您使用的是Rx,因此文本字段的rx.text观察者等效于editChanged操作,应改为使用。该过程中最困难的部分是,如果用户要在字符串的中间插入/删除,请确保不要失去用户的位置。

在您的viewDidLoad中:

textField.rx.text.orEmpty
    .map(digitsOnly)
    .subscribe(onNext: setPreservingCursor(on: textField))
    .disposed(by: bag)

支持全局功能:

func digitsOnly(_ text: String) -> String {
    return text.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
}

func setPreservingCursor(on textField: UITextField) -> (_ newText: String) -> Void {
    return { newText in
        let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: textField.selectedTextRange!.start) + newText.count - (textField.text?.count ?? 0)
        textField.text = newText
        if let newPosition = textField.position(from: textField.beginningOfDocument, offset: cursorPosition) {
            textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
        }
    }
}

顺便说一句,即使您正在展示数字键盘,您仍然需要这样的代码,因为用户可能已经连接了蓝牙键盘,因此仍然可以输入非数字。

答案 1 :(得分:-1)

您可以观察文本更新并在必要时将其还原:

Observable.zip(textfield.rx.text, textfield.rx.text.skip(1))
    .subscribe(onNext: { (old, new) in
        if $invalid {
            textfield.text = old
        }
    })