构建一个iOS前端以使用RxSwift验证数字代码

在某些情况下,通常与无密码身份验证或第二因素身份验证有关,在这种情况下,iOS用户需要输入通过电子邮件或手机短信收到的一些4位或6位数字代码。

这是我们要构建的需求:

  1. 有6位数字的数字代码,因此有6个大的'boxes' 。 每个框只能包含1个数字。
  2. 用户在框中输入数字后,光标会自动跳至下一个。
  3. 用户可以将光标放在任何框上进行更正。 一旦他们点击一个框,框就会变空。 然后,用户可以输入一个新数字。
  4. 在任何给定时间,如果所有框均已完全填写,则“ 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 
边框样式:无
键盘类型:数字键盘

情节提要中的其余作品都涉及放置正确的约束。

在离开情节提要之前,创建一个标签为VerifyButton 。 将其enabled属性设置为false,并将alpha为0.25。 我们希望默认情况下“ Verify按钮显示为禁用状态。

第一个要求是作为TextField每个框只能包含一个数字。 以下关于StackOverflow的答案就是正确的解决方案。 因此,我们创建一个名为LimitLengthTextField.swift的文件,其内容如下:

回到Storyboard,并确保我们将TextField的Max Length设置为1,就像上面的StackOverflow答案所描述的那样。

接下来,我们准备将RxSwiftRxCocoa添加到Podfile

然后将它们导入到ViewController类(记住将这些IBOutlet连接到Storyboard):

现在我们将开始添加一些non-RxSwift代码:

  1. 我们从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有一个名为.editingChangedUIControl.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中构建数字代码验证的前端的方法。