Swift如何创建OTP验证屏幕并在多个uitextfield上向后检测删除 [英] How to create OTP verification screen and detect delete backward on multiple uitextfield is Swift

查看:126
本文介绍了Swift如何创建OTP验证屏幕并在多个uitextfield上向后检测删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我做这个otp屏幕,但是我有一些收获,

我用一堆uitextfield制作了这个otp屏幕,并给出了它的逻辑,但我只是无法删除我制作的textfield中的num

当我像我的数字的前2个一样填充文本字段时,不会删除文本字段,即使我按下ess backButton也不会起作用.....但是当我填充整个文本字段的数量(在我的情况下是六个)时,它将起作用./p>

所以我必须填写所有六个数字,并且我可以从文本字段中删除该数字,如果仅在文本字段中填写一半,它将无法正常工作.

这是我的代码:

  func textField(_ textField:UITextField,shouldChangeCharacters在范围内:NSRange,replacementString字符串:String)->布尔{if((textField.text?.count)!< 1)&&(string.count> 0){如果textField == txtOTP1 {txtOTP2.becomeFirstResponder()}如果textField == txtOTP2 {txtOTP3.becomeFirstResponder()}如果textField == txtOTP3 {txtOTP4.becomeFirstResponder()}如果textField == txtOTP4 {txtOTP5.becomeFirstResponder()}如果textField == txtOTP5 {txtOTP6.becomeFirstResponder()}如果textField == txtOTP6 {txtOTP6.resignFirstResponder()}textField.text =字符串返回假}否则if(((textField.text?.count)!> = 1)&&(string.count == 0){如果textField == txtOTP2 {txtOTP1.becomeFirstResponder()}如果textField == txtOTP3 {txtOTP2.becomeFirstResponder()}如果textField == txtOTP4 {txtOTP3.becomeFirstResponder()}如果textField == txtOTP5 {txtOTP4.becomeFirstResponder()}如果textField == txtOTP6 {txtOTP5.becomeFirstResponder()}如果textField == txtOTP1 {txtOTP1.resignFirstResponder()}textField.text ="返回假}否则(textField.text?.count)!> = 1 {textField.text =字符串返回假}返回真} 

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

并且根据制造商,他说要解决此问题,我只需要将文本字段的用户交互设置为false并使第一个文本字段成为第一响应者",我认为我只是这样做了,但是我也许做错了....

我真的需要修复这个家伙,谢谢.

解决方案

我更喜欢创建一个自定义文本字段,该字段将在按下deleteBackward键时通知用户,而不是固定该代码.因此,首先子类化UITextField:


 导入UIKitclass SingleDigitField:UITextField {//创建一个布尔属性以保存deleteBackward信息varPressedDelete = false//根据需要自定义文本字段覆盖func willMove(toSuperview newSuperview:UIView?){keyboardType = .numberPadtextAlignment = .centerbackgroundColor = .blueisSecureTextEntry = trueisUserInteractionEnabled = false}//隐藏光标覆盖func caretRect(用于位置:UITextPosition)->CGRect {.zero}//隐藏选择覆盖func selectionRects(用于范围:UITextRange)->[UITextSelectionRect] {[]}//禁用复制粘贴覆盖func canPerformAction(_ action:选择器,withSender发件人:任何?)->布尔{false}//覆盖deleteBackward方法,将属性值设置为true并发送一个操作进行editChanged覆盖func deleteBackward(){pressDelete =真sendActions(用于:.editingChanged)}} 


现在在您的ViewCOntroller中:

 导入UIKit类ViewController:UIViewController {//连接文本字段出口@IBOutlet弱var firstDigitField:SingleDigitField!@IBOutlet弱var secondDigitField:SingleDigitField!@IBOutlet弱var thirdDigitField:SingleDigitField!@IBOutlet弱var fourDigitField:SingleDigitField!覆盖func viewDidLoad(){super.viewDidLoad()//为每个字段添加更改的编辑目标[firstDigitField,secondDigitField,thirdDigitField,fourthDigitField] .forEach {$ 0?.addTarget(self,action:#selector(editingChanged),for:.editingChanged)}//将firsDigitField设为第一响应者firstDigitField.isUserInteractionEnabled = truefirstDigitField.becomeFirstResponder()}//在这里,您可以控制字段中发生的每个更改所发生的情况@objc func editedChanged(__ textField:SingleDigitField){//检查是否按下了deleteBackwards键如果textField.pressedDelete {//重置其状态textField.pressedDelete = false//如果该字段的文本为空,则其内容如果textField.hasText {textField.text ="} 别的 {//否则切换该字段,请辞职第一响应者并激活前一个字段并清空其内容切换textField {情况secondDigitField,thirdDigitField,fourthDigitField:textField.resignFirstResponder()textField.isUserInteractionEnabled = false切换textField {案例secondDigitField:firstDigitField.isUserInteractionEnabled = truefirstDigitField.becomeFirstResponder()firstDigitField.text ="案例thirdDigitField:secondDigitField.isUserInteractionEnabled = truesecondDigitField.becomeFirstResponder()secondDigitField.text ="案例fourDigitField:thirdDigitField.isUserInteractionEnabled = truethirdDigitField.becomeFirstResponder()thirdDigitField.text ="默认:休息}默认值:break}}}//确保只有一个字符并且是一个数字,否则请删除其内容保护textField.text?.count == 1,textField.text?.last?.isWholeNumber == true else {textField.text ="返回}//切换textField,辞职第一个响应者并使下一个字段处于活动状态切换textField {情况firstDigitField,secondDigitField,thirdDigitField:textField.resignFirstResponder()textField.isUserInteractionEnabled = false切换textField {案例firstDigitField:secondDigitField.isUserInteractionEnabled = truesecondDigitField.becomeFirstResponder()案例secondDigitField:thirdDigitField.isUserInteractionEnabled = truethirdDigitField.becomeFirstResponder()案例thirdDigitField:fourDigitField.isUserInteractionEnabled = truefourDigitField.becomeFirstResponder()默认值:break}案例fourDigitField:fourDigitField.resignFirstResponder()默认值:break}}} 


Xcode 12示例项目

so i make this otp screen but i have some catch,

i make this otp screen with bunch of uitextfield and i make the logic of it, but i just cant delete on of the num in the textfield that i make

the textfield wont delete when i fill like the first 2 of my num, even i pressess backButton it wont work.....but it will work when i fill the whole num of textfield, in my case is six.

so i have to fill all six of the number and i can delete the number from the textfield, it wont work if only half fill in the textfield.

heres my code :

 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
}

thats the code i use to make the otp uitextField logic......please tell me i know theres something wrong with my logic, thanks.

and according to the maker, he said that to fix this issue i just need to "set user interactions for textfield false and make first textfield first responder", i think i just did that but i maybe i did it wrong....

i really need to fix this guys, thanks.

解决方案

Instead of fixing that code I prefer to create a custom text field that would inform when the deleteBackward key is pressed. So first subclass a 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)
    }
}


Now in your 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

这篇关于Swift如何创建OTP验证屏幕并在多个uitextfield上向后检测删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆