How to navigate through textfields (Next / Done Bu

2018-12-31 20:47发布

How can I navigate through all my text fields with the "Next" Button on the iPhone Keyboard?

The last text field should close the Keyboard.

I've setup the IB the Buttons (Next / Done) but now I'm stuck.

I implemented the textFieldShouldReturn action but now the Next and Done Buttons close the Keyboard.

30条回答
路过你的时光
2楼-- · 2018-12-31 21:39

This is a simple solution in swift, with no tag using, no storyboard tricks...

Just use this extension :

extension UITextField{

    func nextTextFieldField() -> UITextField?{
        //field to return
        var returnField : UITextField?
        if self.superview != nil{
            //for each view in superview
            for (_, view) in self.superview!.subviews.enumerate(){
                //if subview is a text's field
                if view.isKindOfClass(UITextField){
                    //cast curent view as text field
                    let currentTextField = view as! UITextField
                    //if text field is after the current one
                    if currentTextField.frame.origin.y > self.frame.origin.y{
                        //if there is no text field to return already
                        if returnField == nil {
                            //set as default return
                            returnField = currentTextField
                        }
                            //else if this this less far than the other
                        else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
                            //this is the field to return
                            returnField = currentTextField
                        }
                    }
                }
            }
        }
        //end of the mdethod
        return returnField
    }

}

And call it like this (for example) with your textfield delegate:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}
查看更多
与君花间醉酒
3楼-- · 2018-12-31 21:39

you can use IQKeyboardManager library to do this. it handle every thing, you don't need any additional setup.IQKeyboardManager is available through CocoaPods, to install it simply add the following line to your Podfile:

pod 'IQKeyboardManager'

or Just drag and drop IQKeyBoardManager directory from demo project to your project. That's it. you can find IQKeyBoardManager directory from https://github.com/hackiftekhar/IQKeyboardManager

查看更多
路过你的时光
4楼-- · 2018-12-31 21:42

In Cocoa for Mac OS X, you have the next responder chain, where you can ask the text field what control should have focus next. This is what makes tabbing between text fields work. But since iOS devices do not have a keyboard, only touch, this concept has not survived the transition to Cocoa Touch.

This can be easily done anyway, with two assumptions:

  1. All "tabbable" UITextFields are on the same parent view.
  2. Their "tab-order" is defined by the tag property.

Assuming this you can override textFieldShouldReturn: as this:

-(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.
}

Add some more code, and the assumptions can be ignored as well.

Swift 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
}

If the superview of the text field will be a UITableViewCell then next responder will be

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
查看更多
残风、尘缘若梦
5楼-- · 2018-12-31 21:42

A swift extension that applies mxcl's answer to make this particularly easy (adapted to swift 2.3 by Traveler):

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)
    }
}

It's easy to use:

UITextField.connectFields([field1, field2, field3])

The extension will set the return button to "Next" for all but the last field and to "Done" for the last field, and shift focus / dismiss the keyboard when these are tapped.

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)
    }
}

SWIFT 3: use like this -

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)
        }
    }
查看更多
人气声优
6楼-- · 2018-12-31 21:42

I've just created new Pod when dealing with this stuff GNTextFieldsCollectionManager. It automatically handles next/last textField problem and is very easy to use:

[[GNTextFieldsCollectionManager alloc] initWithView:self.view];

Grabs all textfields sorted by appearing in view hierarchy (or by tags), or you can specify your own array of textFields.

查看更多
荒废的爱情
7楼-- · 2018-12-31 21:42

I rather prefer to:

@interface MyViewController : UIViewController
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
@end

In the NIB file I hook the textFields in the desired order into this inputFields array. After that I do a simple test for the index of the UITextField that reports that the user tapped return:

// 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;
}
查看更多
登录 后发表回答