如何创建 OTP 验证屏幕并在多个 uitextfield 上检测向后删除是 Swift
How to create OTP verification screen and detect delete backward on multiple uitextfield is Swift
所以我制作了这个 otp 屏幕,但我有一些收获,
我用一堆 uitextfield 制作了这个 otp 屏幕,我制作了它的逻辑,但我无法删除我制作的文本字段中的 num
当我像数字的前两个一样填充时,文本字段不会删除,即使我按下后退按钮它也不会工作.....但是当我填充整个文本字段时它会工作,在我的例子中是六个.
所以我必须填写所有六个数字,我可以从文本字段中删除数字,如果文本字段只填写一半,它将无法工作。
这是我的代码:
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 并使第一个文本字段成为第一响应者”,我想我只是这样做了但我可能做错了....
我真的需要解决这个问题,谢谢。
我更愿意创建一个自定义文本字段,而不是修复该代码,以便在按下 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 {
[=11=]?.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
}
}
}
所以我制作了这个 otp 屏幕,但我有一些收获,
我用一堆 uitextfield 制作了这个 otp 屏幕,我制作了它的逻辑,但我无法删除我制作的文本字段中的 num
当我像数字的前两个一样填充时,文本字段不会删除,即使我按下后退按钮它也不会工作.....但是当我填充整个文本字段时它会工作,在我的例子中是六个.
所以我必须填写所有六个数字,我可以从文本字段中删除数字,如果文本字段只填写一半,它将无法工作。
这是我的代码:
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 并使第一个文本字段成为第一响应者”,我想我只是这样做了但我可能做错了....
我真的需要解决这个问题,谢谢。
我更愿意创建一个自定义文本字段,而不是修复该代码,以便在按下 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 {
[=11=]?.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
}
}
}