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

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

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

我实现了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.

其他回答

如果有人想这样。我认为这是最接近问题所要求的要求

下面是我如何实现它

为需要设置的每个文本字段添加附件视图,使用

func setAccessoryViewFor(textField : UITextField)    {
    let toolBar = UIToolbar()
    toolBar.barStyle = .default
    toolBar.isTranslucent = true
    toolBar.sizeToFit()

    // Adds the buttons

    // Add previousButton
    let prevButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(previousPressed(sender:)))
    prevButton.tag = textField.tag
    if getPreviousResponderFor(tag: textField.tag) == nil {
        prevButton.isEnabled = false
    }

    // Add nextButton
    let nextButton = UIBarButtonItem(title: ">", style: .plain, target: self, action: #selector(nextPressed(sender:)))
    nextButton.tag = textField.tag
    if getNextResponderFor(tag: textField.tag) == nil {
        nextButton.title = "Done"
    }

    let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    toolBar.setItems([prevButton,spaceButton,nextButton], animated: false)
    toolBar.isUserInteractionEnabled = true
    textField.inputAccessoryView = toolBar
}

使用以下函数来处理轻拍

func nextPressed(sender : UIBarButtonItem) {
    if let nextResponder = getNextResponderFor(tag: sender.tag) {
        nextResponder.becomeFirstResponder()
    } else {
        self.view.endEditing(true)
    }

}

func previousPressed(sender : UIBarButtonItem) {
    if let previousResponder = getPreviousResponderFor(tag : sender.tag)  {
        previousResponder.becomeFirstResponder()
    }
}

func getNextResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag + 1) as? UITextField
}

func getPreviousResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag - 1) as? UITextField
}

您需要按您希望下一个/前一按钮响应的顺序给出textFields标记。

下面是一个swift3版本的Anth0的答案。我把它贴在这里,以帮助任何想要利用他的伟大答案的敏捷开发人员!当您设置关联对象时,我擅自添加了一个返回键类型“Next”。

extension UITextField {

  @nonobjc static var NextHashKey: UniChar = 0

  var nextTextField: UITextField? {
    get {
      return objc_getAssociatedObject(self, 
        &UITextField.NextHashKey) as? UITextField
    }
    set(next) {
     self.returnKeyType = UIReturnKeyType.next
     objc_setAssociatedObject(self,
      &UITextField.NextHashKey,next,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
}

下面是另一个扩展,它显示了使用上述代码循环遍历UITextFields列表的可能性。

extension UIViewController: UITextFieldDelegate {
 public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
   guard let next = textField.nextTextField else {
     textField.resignFirstResponder()
     return true
   }

    next.becomeFirstResponder()
    return false
  }
}

然后在你的ViewController或者其他地方,你可以像这样设置你的文本框。

@IBOutlet fileprivate weak var textfield1: UITextField!
@IBOutlet fileprivate weak var textfield2: UITextField!
@IBOutlet fileprivate weak var textfield3: UITextField!

...

[textfield1, textfield2, textfield3].forEach{ $0?.delegate = self }

textfield1.nextTextField = textfield2
textfield2.nextTextField = textfield3
// We don't assign a nextTextField to textfield3 because we want 
// textfield3 to be the last one and resignFirstResponder when 
// the return button on the soft keyboard is tapped.

Swift 3解决方案,使用UITextField的有序数组

func nextTextField() {
    let textFields = // Your textfields array

    for i in 0 ..< textFields.count{
        if let textfield = textFields[i], textfield.isFirstResponder{
            textfield.resignFirstResponder()
            if i+1 < textFields.count, let nextextfield = textFields[i+1]{
                nextextfield.becomeFirstResponder()
                return
            }
        }
    }
}

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

这是我对这个问题的解决方案。

为了解决这个问题(因为我讨厌依赖标签来做事情),我决定向UITextField对象添加一个自定义属性。换句话说,我在UITextField上创建了一个这样的类别:

UITextField + Extended.h

@interface UITextField (Extended)

@property(retain, nonatomic)UITextField* nextTextField;

@end

UITextField +扩展。m

#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

下面是我如何使用它:

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的链表,每一个都知道下一个是谁。

希望能有所帮助。