如何通过文本框导航

在iPhone键盘上怎样才能使用“下一步”按钮通过文本框导航?
最后一个文本框用来关闭键盘。
我已经设置了IB(下一步/完成)按钮,就进行不下去了。
我执行了textFieldShouldReturn,但是下一步和完成按钮关闭了键盘。
谢谢大家帮助!

原问题:How to navigate through textfields (Next / Done Buttons)

阅读 3.8k
1 个回答

PeyloW
在Mac OS X 的Cocoa里,有下一个响应链,可以解决文本框下一个应该控制什么。这完成文本框之间的切换工作。但是由于iPhone没有键盘,只有触屏,所以这个概念没有顺利迁移到Cocoa Touch上。
无论如何,在下面两个前提下,这个还是容易解决的:

  1. 所以可切换的UITextFields在同一个父视图里。
  2. 切换顺序是通过TAG资源定义的。

假设这个可以覆盖textFieldShouldReturn,像下面这样:

-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
  NSInteger nextTag = textField.tag + 1;
  // 尝试查找下一个响应
  UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
  if (nextResponder) {
    //发现下一个响应,所以设置
    [nextResponder becomeFirstResponder];
  } else {
//没有找到,所以移除键盘
    [textField resignFirstResponder];
  }
  return NO; // 不想让UITextField插入换行符.
}

再加一些代码,这些假设也可以被忽略。


Answerbot
有一个更好的解决办法,我第一次看到觉得不错,好处如下:

  • 回归OSX的文本框实现,导航下一步是什么
  • 不需要依靠TAG
  • 可以扩展到UITextField 和 UITextView控制,或者其他UI控制的键盘。
  • 不会因为标准文本的UITextField委托代码弄乱视图控制器
  • 很好地整合了IB ,可以通过相似的选择拖放链接网店
  • 可以通过熟悉的拖拽方式链接outlet

创建一个UITextField子集合,这个子集合拥有名叫nextField 的IBOutlet 资源。这是头文件:

@interface SOTextField : UITextField

@property (nonatomic, readwrite, assign) IBOutlet UITextField *nextField; 

@end 

这是执行:

@implementation SOTextField

@synthesize nextField;

@end 

在视图控制器里, 你将创建 -textFieldShouldReturn: 委托方法:

- (BOOL) textFieldShouldReturn:(UITextField *) textField {

    BOOL didResign = [textField resignFirstResponder];
    if (!didResign) return NO;

    if ([textField isKindOfClass:[SOTextField class]])
        dispatch_async(dispatch_get_current_queue(), 
           ^ { [[(SOTextField *)textField nextField] becomeFirstResponder]; });

    return YES;

}

在IB里。改变UITextFields使用SOTextField类。接着,还是在IB里,为每个SOTextFields设置委托至文件的所有者(放置委托函数textFieldShouldReturn的地方)。这个设计的优点在于,在任何的textField右键分配nextField出口到你所想让它成为下一个响应的SOTextField对象。
请输入图片描述
再者,还可以循环textField,使最后一个失去焦点时,第一个又成为焦点。
这个很容易被扩展到自动分配SOTextField的returnKeyType到UIReturnKeyNext,如果在有一个被分配的nextField——少一个手动配置的情况下。


Anth0
这是我的解决方案。
为了解决这一问题,我决定给UITextField对象添加一个自定义属性。换句话说我在UITextField创建一个这样的类:
UITextField+Extended.h

<strong><i>@interface UITextField (Extended)

@property(retain, nonatomic)UITextField* nextTextField;

@end </i></strong>

UITextField+Extended.m

<strong><i>#import "UITextField+Extended.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UITextField (Extended)

- (UITextField*) nextTextField { 
    return objc_getAssociatedObject(self, &defaultHashKey); 
}

- (void) setNextTextField:(UITextField *)nextTextField{
    objc_setAssociatedObject(self, &defaultHashKey, nextTextField, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end </i></strong>

现在,看看我怎么使用它:

UITextField *textField1 = ...init your textfield
UITextField *textField2 = ...init your textfield
UITextField *textField3 = ...init your textfield

textField1.nextTextField = textField2;
textField2.nextTextField = textField3;
textField3.nextTextField = nil;

执行textFieldShouldReturn函数:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {

    UITextField *next = theTextField.nextTextField;
    if (next) {
        [next becomeFirstResponder];
    } else {
        [theTextField resignFirstResponder];
    }

    return NO; 
}

现在我有了一种UITextField 链表,每一个都知道下一个是什么。
希望对你有所帮助。


jcrowson
这有一个非常简单的方法当按下“完成”键是驳回键盘。
在头文件里创建一个新的IBAction:

- (IBAction)textFieldDoneEditing:(id)sender;

在执行文件里(.m file)里添加下述函数:

In the implementation file (.m file) add the following method:
- (IBAction)textFieldDoneEditing:(id)sender 
{ 
  [sender resignFirstResponder];
}

然后,当你链接IBAction至textfield,连接到Did End On Exit事件。


Marquee
I我喜欢 OO 解决办法, Anth0和Answerbot都已提到过。然而,我正在做一个快而小的POC,我不想用子类和类别弄乱东西。
另一个简单的解决办法是创建字段的NSArray,当按下“下一步”的时候查找下一个。这不是00方法,但是简单、快捷、易执行。另外,你可以一目了然地查看和修改顺序。
这是我写的代码:

@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;
}
  • 我总是返回NO,因为我不想插入换行符。只想指出这一点,返回YES将自动退出后续字段或者在TextView插入换行符。我花费了好一番时间才弄清楚。
  • 如果你有相似的代码,确保在改变第一个响应之前指定activeField。改变首个响应时即刻的,将立即触发KeyboardWasShown事件。

KronoS
我已经完善了PeyloW的回答,以防你想实现上一个/下一个按钮的功能。

- (IBAction)moveThroughTextFields:(UIBarButtonItem *)sender 
{
    NSInteger nextTag;
    UITextView *currentTextField = [self.view findFirstResponderAndReturn];

    if (currentTextField != nil) {
        //指定按钮的标签  0 代表上一个  1代表下一个
        if (sender.tag == 0) {
            nextTag = currentTextField.tag - 1;

        } else if (sender.tag == 1) {
            nextTag = currentTextField.tag + 1;
        }
    }
    // 尝试查找下一个响应
    UIResponder* nextResponder = [self.view viewWithTag:nextTag];
    if (nextResponder) {
        //发现下一个响应,所以请设置
        // 我在这里添加了resign 以保证有不同而适当的键盘        [currentTextField resignFirstResponder];
        [nextResponder becomeFirstResponder];
    } else {
        //没有找到,所以移除键盘
        [currentTextField resignFirstResponder];

    }
}

继承 UIView是这样的:

@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
    for (UITextView *subView in self.subviews) {
        if (subView.isFirstResponder){
            return subView;
        }
    }
    return nil;
}
@end
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题