我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
当前回答
我在我的故事板中有大约10+ UITextField,我启用下一个功能的方式是通过创建一个UITextField数组,并使下一个UITextField成为firstResponder。下面是实现文件:
#import "RegistrationTableViewController.h"
@interface RegistrationTableViewController ()
@property (weak, nonatomic) IBOutlet UITextField *fullNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet UITextField *address2TextField;
@property (weak, nonatomic) IBOutlet UITextField *cityTextField;
@property (weak, nonatomic) IBOutlet UITextField *zipCodeTextField;
@property (weak, nonatomic) IBOutlet UITextField *urlTextField;
@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
@property (weak, nonatomic) IBOutlet UITextField *confirmPWTextField;
@end
NSArray *uiTextFieldArray;
@implementation RegistrationTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"view did load");
uiTextFieldArray = @[self.fullNameTextField,self.addressTextField,self.address2TextField,self.cityTextField,self.zipCodeTextField,self.urlTextField,self.usernameTextField,self.emailTextField,self.passwordTextField,self.confirmPWTextField];
for(UITextField *myField in uiTextFieldArray){
myField.delegate = self;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
long index = [uiTextFieldArray indexOfObject:textField];
NSLog(@"%ld",index);
if(index < (uiTextFieldArray.count - 1)){
[uiTextFieldArray[++index] becomeFirstResponder];
}else{
[uiTextFieldArray[index] resignFirstResponder];
}
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
其他回答
我用Michael G. Emmons的答案已经有一年了,效果很好。我最近注意到,立即调用resignFirstResponder,然后立即调用becomeFirstResponder会导致键盘“故障”,消失,然后立即出现。我稍微改变了他的版本,跳过resignFirstResponder如果nextField是可用的。
- (BOOL)textFieldShouldReturn:(UITextField *)textField { if ([textField isKindOfClass:[NRTextField class]]) { NRTextField *nText = (NRTextField*)textField; if ([nText nextField] != nil){ dispatch_async(dispatch_get_main_queue(), ^ { [[nText nextField] becomeFirstResponder]; }); } else{ [textField resignFirstResponder]; } } else{ [textField resignFirstResponder]; } return true; }
我喜欢Anth0和Answerbot已经提出的面向对象解决方案。然而,我正在开发一个快速而小型的POC,所以我不想让子类和类别使事情变得混乱。
另一个简单的解决方案是创建一个字段的NSArray,并在按下next时查找下一个字段。不是面向对象的解决方案,而是快速、简单且易于实现。此外,您可以一目了然地查看和修改排序。
下面是我的代码(基于这个线程中的其他答案):
@property (nonatomic) NSArray *fieldArray;
- (void)viewDidLoad {
[super viewDidLoad];
fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
}
- (BOOL) textFieldShouldReturn:(UITextField *) textField {
BOOL didResign = [textField resignFirstResponder];
if (!didResign) return NO;
NSUInteger index = [self.fieldArray indexOfObject:textField];
if (index == NSNotFound || index + 1 == fieldArray.count) return NO;
id nextField = [fieldArray objectAtIndex:index + 1];
activeField = nextField;
[nextField becomeFirstResponder];
return NO;
}
I always return NO because I don't want a line break inserted. Just thought I'd point that out since when I returned YES it would automatically exit the subsequent fields or insert a line break in my TextView. It took me a bit of time to figure that out. activeField keeps track of the active field in case scrolling is necessary to unobscure the field from the keyboard. If you have similar code, make sure you assign the activeField before changing the first responder. Changing first responder is immediate and will fire the KeyboardWasShown event immediately.
没有usings标签,也没有为nextField/nextTextField添加属性,你可以尝试模拟TAB,其中"testInput"是你当前的活动字段:
if ([textInput isFirstResponder])
[textInput.superview.subviews enumerateObjectsAtIndexes:
[NSIndexSet indexSetWithIndexesInRange:
NSMakeRange([textInput.superview.subviews indexOfObject:textInput]+1,
[textInput.superview.subviews count]-[textInput.superview.subviews indexOfObject:textInput]-1)]
options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
*stop = !obj.hidden && [obj becomeFirstResponder];
}];
if ([textInput isFirstResponder])
[textInput.superview.subviews enumerateObjectsAtIndexes:
[NSIndexSet indexSetWithIndexesInRange:
NSMakeRange(0,
[textInput.superview.subviews indexOfObject:textInput])]
options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
*stop = !obj.hidden && [obj becomeFirstResponder];
}];
我很惊讶,这里有这么多答案没有理解一个简单的概念:在应用程序中的控件中导航不是视图本身应该做的事情。控制器的工作是决定将哪个控件作为下一个第一响应器。
此外,大多数答案只适用于前进导航,但用户也可能想后退。
这就是我想到的。表单应该由视图控制器管理,视图控制器是响应器链的一部分。所以你可以完全自由地实现以下方法:
#pragma mark - Key Commands
- (NSArray *)keyCommands
{
static NSArray *commands;
static dispatch_once_t once;
dispatch_once(&once, ^{
UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(tabForward:)];
UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];
commands = @[forward, backward];
});
return commands;
}
- (void)tabForward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.firstObject becomeFirstResponder];
}
- (void)tabBackward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls.reverseObjectEnumerator) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.lastObject becomeFirstResponder];
}
额外的逻辑滚动屏幕外的响应可见之前可能适用。
这种方法的另一个优点是,您不需要子类化您可能想要显示的所有类型的控件(如UITextFields),而是可以在控制器级别管理逻辑,老实说,在控制器级别管理逻辑是正确的。
我尝试使用一种更复杂的方法来解决这个问题,该方法基于为UITableView中的每个单元格(或UITextField)分配一个稍后可以检索的唯一标签值: activate-next-uitextfield-in-uitableview-ios
我希望这能有所帮助!