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

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

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

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


当前回答

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

其他回答

这对我在Xamarin很有效。iOS / Monotouch。 将键盘按钮更改为Next,将控件传递给下一个UITextField,并将键盘隐藏在最后一个UITextField之后。

private void SetShouldReturnDelegates(IEnumerable<UIView> subViewsToScout )
{
  foreach (var item in subViewsToScout.Where(item => item.GetType() == typeof (UITextField)))
  {
    (item as UITextField).ReturnKeyType = UIReturnKeyType.Next;
    (item as UITextField).ShouldReturn += (textField) =>
    {
        nint nextTag = textField.Tag + 1;
        var nextResponder = textField.Superview.ViewWithTag(nextTag);
        if (null != nextResponder)
            nextResponder.BecomeFirstResponder();
        else
            textField.Superview.EndEditing(true); 
            //You could also use textField.ResignFirstResponder(); 

        return false; // We do not want UITextField to insert line-breaks.
    };
  }
}

在ViewDidLoad里面你会有:

如果你的TextFields没有标签设置它现在:

txtField1.Tag = 0;
txtField2.Tag = 1;
txtField3.Tag = 2;
//...

只是一个电话

SetShouldReturnDelegates(yourViewWithTxtFields.Subviews.ToList());
//If you are not sure of which view contains your fields you can also call it in a safer way:
SetShouldReturnDelegates(txtField1.Superview.Subviews.ToList());
//You can also reuse the same method with different containerViews in case your UITextField are under different views.

在Mac OS X的Cocoa中,你有下一个响应器链,在那里你可以询问文本字段下一个控件应该有焦点。这就是在文本字段之间进行标签操作的原因。但由于iOS设备没有键盘,只有触摸,所以这一概念没有在Cocoa touch的过渡中幸存下来。

这很容易做到,只要有两个假设:

所有“tabbable”UITextFields都在同一个父视图上。 它们的“制表符顺序”由tag属性定义。

假设你可以重写textFieldShouldReturn:如下:

-(BOOL)textFieldShouldReturn:(UITextField*)textField
{
  NSInteger nextTag = textField.tag + 1;
  // Try to find next responder
  UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
  if (nextResponder) {
    // Found next responder, so set it.
    [nextResponder becomeFirstResponder];
  } else {
    // Not found, so remove keyboard.
    [textField resignFirstResponder];
  }
  return NO; // We do not want UITextField to insert line-breaks.
}

添加更多的代码,也可以忽略这些假设。

斯威夫特4.0

 func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let nextTag = textField.tag + 1
    // Try to find next responder
    let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder!

    if nextResponder != nil {
        // Found next responder, so set it
        nextResponder?.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard
        textField.resignFirstResponder()
    }

    return false
}

如果文本字段的superview是一个UITableViewCell那么下一个responder将是

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!

下面是一个在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

下面是一个没有授权的例子:

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中的上述代码来做)。

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

更接近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分配-少一个手动配置的东西。