场景:我有4个UITextField只接受1个字符。容易。
问题:输入1个字符后,我希望下一个TextField自动变为活动而不必按下一个(即我使用的是UIKeyboardTypeNumberPad,并且没有NEXT按钮。(我知道我实际上可以创建下一个)按钮编程,但我不想走那么远,只需要输入1个字符后自动激活下一个字段。
#define MAX_LENGTH 1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if (![myCharSet characterIsMember:c]) {
return NO;
}
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 1) ? NO : YES;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == pc1) {
[pc2 becomeFirstResponder];
}else if (textField == pc2) {
[pc3 becomeFirstResponder];
}else if (textField == pc3) {
[pc4 becomeFirstResponder];
}else if (textField == pc4) {
[textField resignFirstResponder];
}
return YES;
}
答案 0 :(得分:19)
我通过修改我在这里找到的一些代码来找到解决方案: http://www.thepensiveprogrammer.com/2010/03/customizing-uitextfield-formatting-for.html
首先将视图控制器设置为文本字段的委托。
然后做这样的事情:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
BOOL shouldProcess = NO; //default to reject
BOOL shouldMoveToNextField = NO; //default to remaining on the current field
int insertStringLength = [string length];
if(insertStringLength == 0){ //backspace
shouldProcess = YES; //Process if the backspace character was pressed
}
else {
if([[textField text] length] == 0) {
shouldProcess = YES; //Process if there is only 1 character right now
}
}
//here we deal with the UITextField on our own
if(shouldProcess){
//grab a mutable copy of what's currently in the UITextField
NSMutableString* mstring = [[textField text] mutableCopy];
if([mstring length] == 0){
//nothing in the field yet so append the replacement string
[mstring appendString:string];
shouldMoveToNextField = YES;
}
else{
//adding a char or deleting?
if(insertStringLength > 0){
[mstring insertString:string atIndex:range.location];
}
else {
//delete case - the length of replacement string is zero for a delete
[mstring deleteCharactersInRange:range];
}
}
//set the text now
[textField setText:mstring];
[mstring release];
if (shouldMoveToNextField) {
//
//MOVE TO NEXT INPUT FIELD HERE
//
}
}
//always return no since we are manually changing the text field
return NO;
}
答案 1 :(得分:7)
我知道这是一个非常旧问题,但这是我的方法,只允许四个UITextField中的单个数值,并自动“标记”到下一个(pin1-pin4每个代表一个PIN号码数字lol,并保留为属性):
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
if (textField == pin1)
{
[pin2 becomeFirstResponder];
}
else if (textField == pin2)
{
[pin3 becomeFirstResponder];
}
else if (textField == pin3)
{
[pin4 becomeFirstResponder];
}
return NO;
}
- (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.2];
}
else if (textField == pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:pin3 afterDelay:0.2];
}
else if (textField == pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:pin4 afterDelay:0.2];
}
}
//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.1];
}
else if (textField == pin3)
{
[self performSelector:@selector(setNextResponder:) withObject:pin2 afterDelay:0.1];
}
else if (textField == pin2)
{
[self performSelector:@selector(setNextResponder:) withObject:pin1 afterDelay:0.1];
}
}
return newLength <= 1;
}
- (void)setNextResponder:(UITextField *)nextResponder
{
[nextResponder becomeFirstResponder];
}
答案 2 :(得分:7)
SWIFT 3更新代码
@IBOutlet weak var tf1: UITextField!
@IBOutlet weak var tf2: UITextField!
@IBOutlet weak var tf3: UITextField!
@IBOutlet weak var tf4: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
tf1.delegate = self
tf2.delegate = self
tf3.delegate = self
tf4.delegate = self
tf1.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
tf2.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
tf3.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
tf4.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tf1.becomeFirstResponder()
}
func textFieldDidChange(textField: UITextField){
let text = textField.text
if text?.utf16.count==1{
switch textField{
case tf1:
tf2.becomeFirstResponder()
case tf2:
tf3.becomeFirstResponder()
case tf3:
tf4.becomeFirstResponder()
case tf4:
tf4.resignFirstResponder()
default:
break
}
}else{
}
}
答案 3 :(得分:4)
以下内容是针对Swift 5的,它将文本字段作为数组而不是单个字段来处理。
import UIKit
class MyViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var digitFields: [UITextField]!
override func viewDidLoad() {
super.viewDidLoad()
digitFields.forEach {
configureDigitField($0)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
digitFields[0].becomeFirstResponder()
}
fileprivate func configureDigitField(_ digitField: UITextField) {
digitField.delegate = (self as UITextFieldDelegate)
digitField.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControl.Event.editingChanged)
}
// Move to next field in digit fields if the value is populated
@objc fileprivate func textFieldDidChange(textField: UITextField) {
if textField.text?.count == 1 {
let remaining = digitFields.filter { $0.text?.count == 0 }
if remaining.count > 0 {
remaining[0].becomeFirstResponder()
} else {
digitFields.forEach { $0.resignFirstResponder() }
}
}
}
结果:
这取决于在数组中分组的文本字段。这可以在界面构建器中通过在“出口配置”屏幕中配置字段集合来实现:
请注意,您需要手动添加
@IBOutlet var digitFields:[UITextField]!
添加到视图控制器,然后才能向其中添加文本字段。
代码行为摘要
答案 4 :(得分:2)
Swift 4.x
textField.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: .editingChanged)
@objc func textFieldDidChange(textField: UITextField)
{
let text = textField.text
if text?.utf16.count == 1 {
switch textField {
case txtOtpNumber1:
txtOtpNumber2.becomeFirstResponder()
case txtOtpNumber2:
txtOtpNumber3.becomeFirstResponder()
case txtOtpNumber3:
txtOtpNumber4.becomeFirstResponder()
case txtOtpNumber4:
txtOtpNumber4.resignFirstResponder()
default:
break
}
} else {
switch textField {
case txtOtpNumber4:
txtOtpNumber3.becomeFirstResponder()
case txtOtpNumber3:
txtOtpNumber2.becomeFirstResponder()
case txtOtpNumber2:
txtOtpNumber1.becomeFirstResponder()
case txtOtpNumber1:
txtOtpNumber1.resignFirstResponder()
default:
break
}
}
}
答案 5 :(得分:1)
虽然这是一个老问题,但我刚刚过来了,我提出了更简单的解决方案。假设我们为传递代码执行此操作,因此每个框(UITextField)最大长度为一个char。
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if (![string isEqualToString:@""]) {
textField.text = string;
if ([textField isEqual:self.txtField1]) {
[self.txtField2 becomeFirstResponder];
}else if ([textField isEqual:self.txtField2]){
[self.txtField3 becomeFirstResponder];
}else if ([textField isEqual:self.txtField3]){
[self.txtField4 becomeFirstResponder];
}else{
[textField resignFirstResponder];
}
return NO;
}
return YES;
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if (textField.text.length > 0) {
textField.text = @"";
}
return YES;
}