我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
当前回答
有一个更优雅的解决方案,让我第一次看到它的时候就大吃一惊。好处:
更接近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分配-少一个手动配置的东西。
其他回答
下面是一个没有授权的例子:
tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
ObjC:
[tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
[tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
使用UIControlEventEditingDidEndOnExit UITextField动作工作(大部分是未知的)。
您还可以很容易地将其连接到故事板中,因此不需要委托或代码。
编辑:实际上我不知道如何在故事板中连接这个。becomeFirstResponder似乎不是这个control-event的一个提供的动作,这是一个遗憾。尽管如此,你可以将所有的文本字段连接到你的ViewController中的一个动作,然后决定哪个textField成为基于发送者的firstresponder(虽然它不像上面的编程解决方案那么优雅,所以IMO用viewDidLoad中的上述代码来做)。
一个快速扩展,应用mxcl的答案,使这特别容易(适应swift 2.3由旅行者):
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
}
}
它很容易使用:
UITextField.connectFields([field1, field2, field3])
扩展将设置返回按钮为“下一步”为所有但最后一个字段和“完成”为最后一个字段,并转移焦点/解散键盘时,这些被轻敲。
Swift < 2.3
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for var i = 0; i < fields.count - 1; i += 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
}
斯威夫特3: 像这样使用-
UITextField.connectFields(fields: [field1, field2])
Extension:
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .next
fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
}
last.returnKeyType = .go
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
}
}
当按下“Done”按钮时,一个非常简单的方法是:
在头文件中创建一个新的IBAction
- (IBAction)textFieldDoneEditing:(id)sender;
在实现文件(。M文件)添加如下方法:
- (IBAction)textFieldDoneEditing:(id)sender
{
[sender resignFirstResponder];
}
然后,当你来链接IBAction到文本框-链接到'Did End On Exit'事件。
我更喜欢:
@interface MyViewController : UIViewController
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
@end
在NIB文件中,我以所需的顺序将textFields钩子到这个inputFields数组中。之后,我做了一个简单的UITextField的索引测试,报告用户点击返回:
// for UITextField
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
NSUInteger index = [_inputFields indexOfObject:textField];
index++;
if (index < _inputFields.count) {
UIView *v = [_inputFields objectAtIndex:index];
[v becomeFirstResponder];
}
return NO;
}
// for UITextView
-(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
if ([@"\n" isEqualToString:text]) {
NSUInteger index = [_inputFields indexOfObject:textView];
index++;
if (index < _inputFields.count) {
UIView *v = [_inputFields objectAtIndex:index];
[v becomeFirstResponder];
} else {
[self.view endEditing:YES];
}
return NO;
}
return YES;
}
下面是一个在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