构建一个iOS前端以使用RxSwift验证数字代码
在某些情况下,通常与无密码身份验证或第二因素身份验证有关,在这种情况下,iOS用户需要输入通过电子邮件或手机短信收到的一些4位或6位数字代码。
这是我们要构建的需求:
- 有6位数字的数字代码,因此有6个大的
'boxes'
。 每个框只能包含1个数字。 - 用户在框中输入数字后,光标会自动跳至下一个。
- 用户可以将光标放在任何框上进行更正。 一旦他们点击一个框,框就会变空。 然后,用户可以输入一个新数字。
- 在任何给定时间,如果所有框均已完全填写,则“
Verify
按钮将变为启用状态。 如果任何框为空,则“Verify
按钮将被禁用。
我称它为'box'
但它只是View
顶部的TextField
,其高度为1个单位。 然后,将它们都放置在垂直的StackView
(这意味着轴是垂直的)。 然后我重复了6次,最后得到其中6个StackView
实例。 现在就像玩乐高游戏一样,我将这些StackView
所有6个实例放置在另一个StackView
。 外部StackView
是水平的。 这是ViewController在情节提要中的屏幕截图:
inner
StackViews
一些关键属性是:
轴:垂直
对齐方式:填充
分布:等距
间距:1
和outer
StackView
:
轴:水平
对齐方式:底部
分布:均等填充
间距:7
数字TextField
一些关键属性:
字体:System 48.0
边框样式:无
键盘类型:数字键盘
情节提要中的其余作品都涉及放置正确的约束。
在离开情节提要之前,创建一个标签为Verify
的Button
。 将其enabled
属性设置为false,并将alpha
为0.25。 我们希望默认情况下“ Verify
按钮显示为禁用状态。
第一个要求是作为TextField
每个框只能包含一个数字。 以下关于StackOverflow的答案就是正确的解决方案。 因此,我们创建一个名为LimitLengthTextField.swift
的文件,其内容如下:
回到Storyboard,并确保我们将TextField
的Max Length设置为1,就像上面的StackOverflow答案所描述的那样。
接下来,我们准备将RxSwift
和RxCocoa
添加到Podfile
:
然后将它们导入到ViewController
类(记住将这些IBOutlet
连接到Storyboard):
现在我们将开始添加一些non-RxSwift
代码:
- 我们从6个单独的
TextField
成员定义了一个UITextField((var digitTextFields: [UITextField] = [])
数组。 在ViewDidLoad()
,我们将如下填充数组:
digitTextFields = [firstDigitTextField,secondDigitTextField,
thirdDigitTextField,thirdDigitTextField,
第五位数字文本字段,第六位数字文本字段]
3.由于我们想在输入框时将每个数字居中,因此添加以下代码
用于digitTextFields中的digitTextField {
digitTextField.textAlignment = .center
digitTextField.contentVerticalAlignment = .center
}
4.创建一个辅助方法来启用或禁用按钮。
func enableButton(button:UIButton,enabled:Bool){
button.isEnabled =启用
button.alpha =已启用? 1.0:0.25
}
此时,我们有以下代码:
5.接下来,我们进入添加RxSwift
代码的令人兴奋的部分。 实例化一个名为disposeBag
的成员变量。 这是出于RxSwift
的内存管理目的,以防止内存泄漏。
var digitTextFields:[UITextField] = []
让disposeBag = DisposeBag()
6.到目前为止, disposeBag
仍仅用于清洁服务。 现在,为了满足“输入数字后,使光标跳至下一个框”的要求,我们将需要一些数据结构。
7.以下数据结构是元组的数组。 每个元组包含一个TextField
(也称为box
)和一个潜在的下一个响应者。 例如,第一个TextField
具有下一个响应者,即第二个TextField
。 这意味着在第一个TextField
输入数字后,光标将自动跳转到第二个TextField
。 另一个示例,第六个TextField没有任何下一个响应者。 在第六个TextField中输入数字后,我们只想关闭数字键盘。 在代码中
让响应者:[(digitTextField:UITextField,
potentialNextResponder:UITextField?)] = [
(firstDigitTextField,secondDigitTextField),
(secondDigitTextField,thirdDigitTextField),
(thirdDigitTextField,thirdDigitTextField),
(fourthDigitTextField,thirdDigitTextField),
(fifthDigitTextField,thirdDigitTextField),
(sixthDigitTextField,无)
]
8. RxSwift
有一个名为.editingChanged
的UIControl.Event
。 对于每个TextField
,我们想从这些异步事件中创建一个Observable
。 我们将创建此Observable
并立即订阅。 在OnNext
处理程序中,我们将根据是否有下一个响应程序来做不同的事情。 如果存在下一个响应者,则下一个响应者将成为第一个响应者。 如果没有,我们只是来自TextField的第一个响应者。 上面的内容听起来很可怕,但是在代码中实际上很容易遵循:
9.对于下一个要求“如果在方框上单击,请清除数字”,该代码与上面的代码非常相似,但有2个区别。 我们感兴趣的事件是UIControl.Event.editingDidBegin
。 第二个区别是在OnNext
处理程序中,我们清除了TextField
并禁用了Verify
按钮。 在代码中:
10.对于最后一个要求,“任何时候都有一个空框,请禁用验证按钮。 否则,启用按钮”,当每个TextField
的文本都更改时,我们可以从中创建一个Observable
。
let digitObservables = digitTextFields.map {$ 0.rx.text.map {$ 0 ?? “”}}
我们将使用Rx运算符combineLatest
创建一个我们订阅的结果Observable
。 在OnNext
处理程序中,如果TextField
任何一个为空,则将Verify
设置为false
,否则设置为true
。
这是完整的文件
RxSwift非常令人惊讶。 它允许以相当简洁的方式表达相当复杂的需求。 无论如何,这就是我们可以使用RxSwift在iOS中构建数字代码验证的前端的方法。