如何通过文本框导航

本文介绍如何在iPhone上通过文本框导航,包括使用下一步和完成按钮控制多个文本框间的焦点转移。提供了多种实现方案,如利用 UIResponder 链、创建 UITextField 子类或使用 NSArray 管理文本框顺序。

本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术。本文将为读者讲解如何通过文本框导航。

问题:

在iPhone键盘上怎样才能使用“下一步”按钮通过文本框导航?

最后一个文本框用来关闭键盘。

我已经设置了IB(下一步/完成)按钮,就进行不下去了。

我执行了textFieldShouldReturn,但是下一步和完成按钮关闭了键盘。

谢谢大家帮助!

答案:

PeyloW

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

无论如何,在下面两个前提下,这个还是容易解决的:

1.所以可切换的UITextFields在同一个父视图里。

2.切换顺序是通过TAG资源定义的。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(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 资源。这是头文件:

1
2
3
4
5
@interface SOTextField : UITextField
 
@property (nonatomic, readwrite, assign) IBOutlet UITextField *nextField;
 
@end

这是执行:

1
2
3
4
5
@implementation SOTextField
 
@synthesize nextField;
 
@end

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

1
2
3
4
5
6
7
8
9
10
11
12
- (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

1
2
3
4
5
<strong><i>@interface UITextField (Extended)
 
@property(retain, nonatomic)UITextField* nextTextField;
 
@end </i></strong>

UITextField+Extended.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>

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

1
2
3
4
5
6
7
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函数:

1
2
3
4
5
6
7
8
9
10
11
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
 
     UITextField *next = theTextField.nextTextField;
     if (next) {
         [next becomeFirstResponder];
     } else {
         [theTextField resignFirstResponder];
     }
 
     return NO;
}

现在我有了一种UITextField 链表,每一个都知道下一个是什么。

希望对你有所帮助。

jcrowson

这有一个非常简单的方法当按下“完成”键是驳回键盘。

在头文件里创建一个新的IBAction:

1
- (IBAction)textFieldDoneEditing:(id)sender;

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

1
2
3
4
5
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方法,但是简单、快捷、易执行。另外,你可以一目了然地查看和修改顺序。

这是我写的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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的回答,以防你想实现上一个/下一个按钮的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (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是这样的:

1
2
3
4
5
6
7
8
9
10
11
@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
     for (UITextView *subView in self.subviews) {
         if (subView.isFirstResponder){
             return subView;
         }
     }
     return nil;
}
@end

原文链接:How to navigate through textfields (Next / Done Buttons)

文章选自StackOverFlow社区,鉴于其内容对于开发者有所帮助,现将文章翻译于此,供大家参考及学习。9Tech将每日持续更新,读者可点击StackOverflow(简称:SOF)精选问答汇总,查看全部译文内容。同时,我们也招募志同道合的技术朋友共同翻译,造福大家!报名请发邮件至zhangqi_wj#cyou-inc.com。(#换成@)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值