UITextField:密码实现
UITextField: Password Implementation
我有一个 OTP 屏幕,我必须在 4 个不同的文本字段中输入 4 位密码的 OTP,场景是这样的:
- 每个文本字段的最大字符数限制为 1,当用户在文本字段中输入字符时,它应该移动到下一个文本字段。
- 当用户点击返回 space 时,它应该返回到上一个文本字段以便进行更改。
我已经完成了 70% 的工作,但是 space 仅当用户输入所有文本字段时才工作。我正在粘贴我的代码。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// This allows numeric text only, but also backspace for deletes
if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
return NO;
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
// This 'tabs' to next field when entering digits
if (newLength == 1) {
if (textField == _pin1)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField ==_pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin4 afterDelay:0];
}
}
//this goes to previous field as you backspace through them, so you don't have to tap into them individually
else if (oldLength > 0 && newLength == 0) {
if (textField ==_pin4)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField == _pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
}
}
return newLength <= 1;
}
- (void)setNextResponder:(UITextField *)nextResponder
{
[nextResponder becomeFirstResponder];
}
工作:
原因是当 UITextField 为 empty
时,它不会检测到 backspace event
。
因此,要在这种情况下检测退格事件,您必须 Subclass
UITextField 并覆盖 deleteBackward
方法。
验证以下内容link了解更多详情。
Detect backspace in UITextField
编辑:添加了代码。
-Subclass 所有 4 个 UITextfield 与以下 class.
@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete:(UITextField *)textField;
@end
@interface MyTextField : UITextField<UIKeyInput>
@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end
@implementation MyTextField
- (void)deleteBackward {
[super deleteBackward];
if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete:)]){
[_myDelegate textFieldDidDelete:self];
}
}
@end
-为所有 UITextField 设置 delegate 为 self,并在 class
中采用 MyTextFieldDelegate 协议
_pin1.myDelegate=self;
_pin2.myDelegate=self;
_pin3.myDelegate=self;
_pin4.myDelegate=self;
-现在实现textFieldDidDelete方法如下
- (void)textFieldDidDelete:(UITextField *)textField {
if (textField ==_pin4)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField == _pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
}
}
希望对您有所帮助。
需要在 StoryBoard
.
中将标签输入 UITextView
喜欢textField1 = 101,textField2 = 102,textField3 = 103,textField4 = 104
将以下代码放入您的 viewcontroller
。
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
BOOL shouldDelete = YES;
if ([textField.text length] == 0 && [textField.text isEqualToString:@""]) {
long tagValue = textField.tag - 1;
UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];
[txtField becomeFirstResponder];
}
return shouldDelete;
}
以下代码为下一个UItextField
重点。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// This allows numeric text only, but also backspace for deletes
if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
return NO;
if ([textField.text length] == 0) {
[self performSelector:@selector(changeTextFieldFocusToNextTextField:) withObject:textField afterDelay:0.3];
}
return YES;
}
-(void)changeTextFieldFocusToNextTextField:(UITextField*)textField{
long tagValue = textField.tag + 1;
UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];
[txtField becomeFirstResponder];
}
示例输出
对于Swift3.x
class CodeConfirmController:ViewController,UITextFieldDelegate{
@IBOutlet weak var digitNum1: UITextField!
@IBOutlet weak var digitNum2: UITextField!
@IBOutlet weak var digitNum3: UITextField!
@IBOutlet weak var digitNum4: UITextField!
override func viewDidLoad() {
digitNum1.delegate = self
digitNum2.delegate = self
digitNum3.delegate = self
digitNum4.delegate = self
}
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
let shouldDelete: Bool = true
if textField.text?.characters.count == 0 && (textField.text == "") {
let tagValue: Int = textField.tag - 1
let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
txtField?.becomeFirstResponder()
}
return shouldDelete
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// This allows numeric text only, but also backspace for deletes
if (string.characters.count ) > 0 && !Scanner(string: string).scanInt32(nil) {
return false
}
if textField.text?.characters.count == 0 {
perform(#selector(self.changeTextFieldFocus(toNextTextField:)), with: textField, afterDelay: 0.1)
}
return true
}
func changeTextFieldFocus(toNextTextField textField: UITextField) {
let tagValue: Int = textField.tag + 1
let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
txtField?.becomeFirstResponder()
}
}
我有一个 OTP 屏幕,我必须在 4 个不同的文本字段中输入 4 位密码的 OTP,场景是这样的:
- 每个文本字段的最大字符数限制为 1,当用户在文本字段中输入字符时,它应该移动到下一个文本字段。
- 当用户点击返回 space 时,它应该返回到上一个文本字段以便进行更改。
我已经完成了 70% 的工作,但是 space 仅当用户输入所有文本字段时才工作。我正在粘贴我的代码。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// This allows numeric text only, but also backspace for deletes
if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
return NO;
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
// This 'tabs' to next field when entering digits
if (newLength == 1) {
if (textField == _pin1)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField ==_pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin4 afterDelay:0];
}
}
//this goes to previous field as you backspace through them, so you don't have to tap into them individually
else if (oldLength > 0 && newLength == 0) {
if (textField ==_pin4)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField == _pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
}
}
return newLength <= 1;
}
- (void)setNextResponder:(UITextField *)nextResponder
{
[nextResponder becomeFirstResponder];
}
工作:
原因是当 UITextField 为 empty
时,它不会检测到 backspace event
。
因此,要在这种情况下检测退格事件,您必须 Subclass
UITextField 并覆盖 deleteBackward
方法。
验证以下内容link了解更多详情。
Detect backspace in UITextField
编辑:添加了代码。
-Subclass 所有 4 个 UITextfield 与以下 class.
@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete:(UITextField *)textField;
@end
@interface MyTextField : UITextField<UIKeyInput>
@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end
@implementation MyTextField
- (void)deleteBackward {
[super deleteBackward];
if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete:)]){
[_myDelegate textFieldDidDelete:self];
}
}
@end
-为所有 UITextField 设置 delegate 为 self,并在 class
中采用 MyTextFieldDelegate 协议 _pin1.myDelegate=self;
_pin2.myDelegate=self;
_pin3.myDelegate=self;
_pin4.myDelegate=self;
-现在实现textFieldDidDelete方法如下
- (void)textFieldDidDelete:(UITextField *)textField {
if (textField ==_pin4)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
}
else if (textField == _pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
}
else if (textField == _pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
}
}
希望对您有所帮助。
需要在 StoryBoard
.
UITextView
喜欢textField1 = 101,textField2 = 102,textField3 = 103,textField4 = 104
将以下代码放入您的 viewcontroller
。
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
BOOL shouldDelete = YES;
if ([textField.text length] == 0 && [textField.text isEqualToString:@""]) {
long tagValue = textField.tag - 1;
UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];
[txtField becomeFirstResponder];
}
return shouldDelete;
}
以下代码为下一个UItextField
重点。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// This allows numeric text only, but also backspace for deletes
if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
return NO;
if ([textField.text length] == 0) {
[self performSelector:@selector(changeTextFieldFocusToNextTextField:) withObject:textField afterDelay:0.3];
}
return YES;
}
-(void)changeTextFieldFocusToNextTextField:(UITextField*)textField{
long tagValue = textField.tag + 1;
UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];
[txtField becomeFirstResponder];
}
示例输出
对于Swift3.x
class CodeConfirmController:ViewController,UITextFieldDelegate{
@IBOutlet weak var digitNum1: UITextField!
@IBOutlet weak var digitNum2: UITextField!
@IBOutlet weak var digitNum3: UITextField!
@IBOutlet weak var digitNum4: UITextField!
override func viewDidLoad() {
digitNum1.delegate = self
digitNum2.delegate = self
digitNum3.delegate = self
digitNum4.delegate = self
}
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
let shouldDelete: Bool = true
if textField.text?.characters.count == 0 && (textField.text == "") {
let tagValue: Int = textField.tag - 1
let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
txtField?.becomeFirstResponder()
}
return shouldDelete
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// This allows numeric text only, but also backspace for deletes
if (string.characters.count ) > 0 && !Scanner(string: string).scanInt32(nil) {
return false
}
if textField.text?.characters.count == 0 {
perform(#selector(self.changeTextFieldFocus(toNextTextField:)), with: textField, afterDelay: 0.1)
}
return true
}
func changeTextFieldFocus(toNextTextField textField: UITextField) {
let tagValue: Int = textField.tag + 1
let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
txtField?.becomeFirstResponder()
}
}