我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?

最后一个文本字段应该关闭键盘。

我已经设置了IB按钮(下一步/完成),但现在我卡住了。

我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。


当前回答

没有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];
                                                    }];

其他回答

有一个更优雅的解决方案,让我第一次看到它的时候就大吃一惊。好处:

更接近OSX文本框的实现,其中一个文本框知道下一步的重点应该去哪里 不依赖于设置或使用标签-这是,IMO脆弱的用例 可以扩展工作与UITextField和UITextView控件-或任何键盘输入UI控件 不会让你的视图控制器与样板UITextField委托代码混淆 很好地与IB集成,并可以通过熟悉的选项-拖放连接插座进行配置。

创建一个UITextField子类,它有一个名为nextField的IBOutlet属性。下面是标题:

@interface SOTextField : UITextField

@property (weak, nonatomic) IBOutlet UITextField *nextField; 

@end

这是它的实现:

@implementation SOTextField

@end

在你的视图控制器中,你将创建-textFieldShouldReturn: delegate方法:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if ([textField isKindOfClass:[SOTextField class]]) {
        UITextField *nextField = [(SOTextField *)textField nextField];

        if (nextField) {
            dispatch_async(dispatch_get_current_queue(), ^{
                [nextField becomeFirstResponder];
            });
        }
        else {
            [textField resignFirstResponder];
        }
    }

    return YES;
}

在IB,改变你的UITextFields使用SOTextField类。接下来,同样在IB中,设置每个“SOTextFields”的委托为“文件的所有者”(这是你把委托方法的代码- textFieldShouldReturn)。这种设计的美妙之处在于,现在你可以简单地右键单击任何textField,并将nextField出口分配给你想成为下一个响应器的下一个SOTextField对象。

此外,您还可以做一些很酷的事情,如循环textFields,以便在最后一个失去焦点后,第一个将再次获得焦点。

这可以很容易地扩展到自动分配SOTextField的returnKeyType到一个UIReturnKeyNext,如果有一个nextField分配-少一个手动配置的东西。

下面是一个在UIControl上使用类别的选项卡实现。这个解决方案具有Michael和Anth0方法的所有优点,但适用于所有uicontrol,而不仅仅是UITextFields。它还可以与接口生成器和故事板无缝工作。

源代码和示例应用程序:UIControlsWithTabbing的GitHub仓库

用法:

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField transferFirstResponderToNextControl];
    return NO;
}

标题:

//
// UIControl+NextControl.h
// UIControlsWithTabbing
//

#import <UIKit/UIKit.h>

@interface UIControl (NextControl)

@property (nonatomic, weak) IBOutlet UIControl *nextControl;

- (BOOL)transferFirstResponderToNextControl;

@end

实现:

#import "UIControl+NextControl.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UIControl (NextControl)

- (UIControl *)nextControl
{
    return objc_getAssociatedObject(self, &defaultHashKey);
}

- (void)setNextControl:(UIControl *)nextControl
{
    objc_setAssociatedObject(self, &defaultHashKey, nextControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)transferFirstResponderToNextControl
{
    if (self.nextControl)
    {
        [self.nextControl becomeFirstResponder];

        return YES;
    }

    [self resignFirstResponder];

    return NO;
}

@end

我刚刚创建了新的Pod处理这些东西GNTextFieldsCollectionManager。它自动处理下一个/最后一个textField问题,非常容易使用:

[[GNTextFieldsCollectionManager alloc] initWithView:self.view];

抓取所有的文本字段排序出现在视图层次结构(或标签),或者你可以指定自己的文本字段数组。

在textFieldShouldReturn你应该检查你目前的文本域不是最后一个,当他们点击下一步,如果不是不要解散键盘..

我喜欢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.