如何创建 OTP 验证屏幕并在多个 uitextfield 上向后检测删除是 Swift

Posted

技术标签:

【中文标题】如何创建 OTP 验证屏幕并在多个 uitextfield 上向后检测删除是 Swift【英文标题】:How to create OTP verification screen and detect delete backward on multiple uitextfield is Swift 【发布时间】:2022-01-03 23:30:21 【问题描述】:

所以我做了这个 otp 屏幕,但我有一些问题,

我用一堆 uitextfield 制作这个 otp 屏幕,我制作了它的逻辑,但我无法删除我制作的文本字段中的 num

当我像我的 num 的前 2 个一样填充时,文本字段不会删除,即使我按下 backButton 它也不起作用.....但是当我填充整个文本字段时它会起作用,在我的情况下是六个。

所以我必须填写所有六个数字,我可以从文本字段中删除数字,如果只填写一半,它将无法工作。

这是我的代码:

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
    
    if ((textField.text?.count)! < 1) && (string.count > 0) 
        if textField == txtOTP1 
            txtOTP2.becomeFirstResponder()
        
        if textField == txtOTP2 
            txtOTP3.becomeFirstResponder()
        
        if textField == txtOTP3 
            txtOTP4.becomeFirstResponder()
        
        if textField == txtOTP4 
            txtOTP5.becomeFirstResponder()
        
        if textField == txtOTP5
            txtOTP6.becomeFirstResponder()
        
        if textField == txtOTP6
            txtOTP6.resignFirstResponder()
        
        
        textField.text = string
        return false
    else if ((textField.text?.count)! >= 1) && (string.count == 0) 
        if textField == txtOTP2
            txtOTP1.becomeFirstResponder()
        
        if textField == txtOTP3
            txtOTP2.becomeFirstResponder()
        
        if textField == txtOTP4
            txtOTP3.becomeFirstResponder()
        
        if textField == txtOTP5
            txtOTP4.becomeFirstResponder()
        
        if textField == txtOTP6
            txtOTP5.becomeFirstResponder()
        
        if textField == txtOTP1
            txtOTP1.resignFirstResponder()
        
    
        textField.text = ""
        return false
    
    else if (textField.text?.count)! >= 1 

        
        textField.text = string
        return false
    
    
    return true

这就是我用来制作 otp uitextField 逻辑的代码......请告诉我,我知道我的逻辑有问题,谢谢。

我在此视频中观看了制作此 otp 屏幕的教程 https://www.youtube.com/watch?v=gZnBXh0TRO8

根据制造商的说法,他说要解决这个问题,我只需要“将文本字段的用户交互设置为 false 并让第一个文本字段成为第一响应者”,我想我只是这样做了,但我可能做错了.. ..

我真的需要解决这个问题,谢谢。

【问题讨论】:

【参考方案1】:

我更愿意创建一个自定义文本字段,而不是修复该代码,以便在按下 deleteBackward 键时发出通知。所以首先继承一个 UITextField:


import UIKit
class SingleDigitField: UITextField 
    // create a boolean property to hold the deleteBackward info
    var pressedDelete = false
    // customize the text field as you wish 
    override func willMove(toSuperview newSuperview: UIView?) 
        keyboardType = .numberPad
        textAlignment = .center
        backgroundColor = .blue
        isSecureTextEntry = true
        isUserInteractionEnabled = false
    
    // hide cursor
    override func caretRect(for position: UITextPosition) -> CGRect  .zero 
    // hide selection
    override func selectionRects(for range: UITextRange) -> [UITextSelectionRect]  [] 
    // disable copy paste
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool  false 
    // override deleteBackward method, set the property value to true and send an action for editingChanged
    override func deleteBackward() 
        pressedDelete = true
        sendActions(for: .editingChanged)
    


现在在您的 ViewCONtroller 中:

import UIKit

class ViewController: UIViewController 
    // connect the textfields outlets
    @IBOutlet weak var firstDigitField: SingleDigitField!
    @IBOutlet weak var secondDigitField: SingleDigitField!
    @IBOutlet weak var thirdDigitField: SingleDigitField!
    @IBOutlet weak var fourthDigitField: SingleDigitField!
    override func viewDidLoad() 
        super.viewDidLoad()
        // add a target for editing changed for each field
        [firstDigitField,secondDigitField,thirdDigitField,fourthDigitField].forEach 
            $0?.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        
        // make the firsDigitField the first responder
        firstDigitField.isUserInteractionEnabled = true
        firstDigitField.becomeFirstResponder()
    
    // here you control what happens to each change that occurs to the fields
    @objc func editingChanged(_ textField: SingleDigitField) 
        // check if the deleteBackwards key was pressed
        if textField.pressedDelete 
            // reset its state
            textField.pressedDelete = false
            // if the field has text empty its content
            if textField.hasText 
                textField.text = ""   
             else 
                // otherwise switch the field, resign the first responder and activate the previous field and empty its contents
                switch textField 
                case secondDigitField, thirdDigitField, fourthDigitField:
                    textField.resignFirstResponder()
                    textField.isUserInteractionEnabled = false
                    switch textField 
                    case secondDigitField:
                        firstDigitField.isUserInteractionEnabled = true
                        firstDigitField.becomeFirstResponder()
                        firstDigitField.text = ""
                    case thirdDigitField:
                        secondDigitField.isUserInteractionEnabled = true
                        secondDigitField.becomeFirstResponder()
                        secondDigitField.text = ""
                    case fourthDigitField:
                        thirdDigitField.isUserInteractionEnabled = true
                        thirdDigitField.becomeFirstResponder()
                        thirdDigitField.text = ""
                    default:
                        break
                    
                default: break
                
            
        
        // make sure there is only one character and it is a number otherwise delete its contents
        guard textField.text?.count == 1, textField.text?.last?.isWholeNumber == true else 
            textField.text = ""
            return
        
        // switch the textField, resign the first responder and make the next field active
        switch textField 
        case firstDigitField, secondDigitField, thirdDigitField:
            textField.resignFirstResponder()
            textField.isUserInteractionEnabled = false
            switch textField 
            case firstDigitField:
                secondDigitField.isUserInteractionEnabled = true
                secondDigitField.becomeFirstResponder()
            case secondDigitField:
                thirdDigitField.isUserInteractionEnabled = true
                thirdDigitField.becomeFirstResponder()
            case thirdDigitField:
                fourthDigitField.isUserInteractionEnabled = true
                fourthDigitField.becomeFirstResponder()
            default: break
            
        case fourthDigitField:
            fourthDigitField.resignFirstResponder()
        default: break
        
    


Xcode 12 sample project

【讨论】:

以上是关于如何创建 OTP 验证屏幕并在多个 uitextfield 上向后检测删除是 Swift的主要内容,如果未能解决你的问题,请参考以下文章

无需注册的 iOS Firebase OTP 验证

在让用户使用pyotp创建新密码之前如何实现基于OTP的验证?

如何验证用户从数据库中的浏览器输入的otp?

如何使用 Firebase android 验证收到的用于手机号码验证的 OTP

如何在swift 4中禁用otp屏幕中文本字段上光标的中间外观

Firebase 身份验证 Flutter 中的电话号码