Switching between Text fields on pressing return k

2019-01-13 02:29发布

问题:

I'm designing an iOS app and I want that when the return key is pressed in my iPhone it directs me to the next following text field.

I have found a couple of similar questions, with excellent answers around but they all just happen to be in Objective-C and I'm looking for Swift code, now this is what I have up until now:

func textFieldShouldReturn(emaillabel: UITextField) -> Bool{
    return true
}

It's placed in the file that's connected and controller to the UIView that contains the text fields, but I'm not sure if thats the right place.

I'm basically new to swift, so explain every little step or i'll manage to mess it up somehow. Also I'm using the latest version of Xcode if that makes any difference.

okay, so I tried this out and got this error:
//could not find an overload for '!=' that accepts the supplied arguments

func textFieldShouldReturn(textField: UITextField) -> Bool {
    let nextTag: NSInteger = textField.tag + 1;
    // Try to find next responder
    let nextResponder: UIResponder = textField.superview!.viewWithTag(nextTag)!
    if (nextResponder != nil) {//could not find an overload for '!=' that accepts the supplied arguments

        // Found next responder, so set it.
        nextResponder.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard.
        textField.resignFirstResponder()
    }
    return false; // We do not want UITextField to insert line-breaks.
}

Thanks in advance pals!!

回答1:

Swift 3.0 (check edit history for previous versions):

class ViewController: UIViewController,UITextFieldDelegate 
{
   //Link each UITextField
   @IBOutlet weak var textField: UITextField!

   override func viewDidLoad() 
   {
      super.viewDidLoad()
      // Do this for each UITextField
      textField.delegate = self
      textField.tag = 0 //Increment accordingly
   }

   func textFieldShouldReturn(_ textField: UITextField) -> Bool 
   {
      // Try to find next responder
      if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
         nextField.becomeFirstResponder()
      } else {
         // Not found, so remove keyboard.
         textField.resignFirstResponder()
      }
      // Do not add a line break
      return false
   }
}

Make sure your UITextField delegates are set and the tags are incremented properly. This can also be done through the Interface Builder.

Here's a link to an Obj-C post I found: How to navigate through textfields (Next / Done Buttons)



回答2:

Swift 4

You can easily switch to another TextField.

  • Add UITextFieldDelegate and add textFieldShouldReturn(_:) method in ViewController
  • Drag from TextField to ViewController in Interface Builder. Then select delegate property. Note : Do this for all TextField
  • Create an IBOutlet for all TextFields

    class ViewController: UIViewController, UITextFieldDelegate {
    
      @IBOutlet weak var txtFieldName: UITextField!
      @IBOutlet weak var txtFieldEmail: UITextField!
      @IBOutlet weak var txtFieldPassword: UITextField!
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
      }
    
      //MARK: - Controlling the Keyboard
      func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    
        if textField == txtFieldName {
           textField.resignFirstResponder()
           txtFieldEmail.becomeFirstResponder()
        } else if textField == txtFieldEmail {
           textField.resignFirstResponder()
           txtFieldPassword.becomeFirstResponder()
        } else if textField == txtFieldPassword {
           textField.resignFirstResponder()
        }
       return true
      }
    }
    


回答3:

I suggest that you should use switch statement in textFieldShouldReturn(_:).

// MARK: UITextFieldDelegate

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    switch textField {
    case nameTextField:
        phoneTextField.becomeFirstResponder()
    case phoneTextField:
        emailTextField.becomeFirstResponder()
    case emailTextField:
        descriptionTextField.becomeFirstResponder()
    default:
        textField.resignFirstResponder()
    }
    return false
}


回答4:

This approach needs some changes in table views and collection views, but it's okay for simple forms I guess.

Connect your textFields to one IBOutletCollection, sort it by its y coordinate and in textFieldShouldReturn(_:) just jump to the next textfield until you reach the end:

@IBOutlet var textFields: [UITextField]!

...

textFields.sortInPlace { $0.frame.origin.y < $1.frame.origin.y }

...

func textFieldShouldReturn(textField: UITextField) -> Bool {
    if let currentIndex = textFields.indexOf(textField) where currentIndex < textFields.count-1 {
        textFields[currentIndex+1].becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return true
}    

Or just look at sample project (xcode 7 beta 4)



回答5:

I have tried many codes and finally this worked for me in Swift 3.0 Latest [March 2017]

The "ViewController" class should inherited the "UITextFieldDelegate" for making this code working.

class ViewController: UIViewController,UITextFieldDelegate  

Add the Text field with the Proper Tag nuber and this tag number is used to take the control to appropriate text field based on incremental tag number assigned to it.

override func viewDidLoad() {

 userNameTextField.delegate = self

        userNameTextField.tag = 0

        userNameTextField.returnKeyType = UIReturnKeyType.next

        passwordTextField.delegate = self

        passwordTextField.tag = 1


        passwordTextField.returnKeyType = UIReturnKeyType.go

}

In the above code, the "returnKeyType = UIReturnKeyType.next" where will make the Key pad return key to display as "Next" you also have other options as "Join/Go" etc, based on your application change the values.

This "textFieldShouldReturn" is a method of UITextFieldDelegate controlled and here we have next field selection based on the Tag value incrementation

func textFieldShouldReturn(_ textField: UITextField) -> Bool

    {

        if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {

            nextField.becomeFirstResponder()

        } else {

            textField.resignFirstResponder()

            return true;

        }

        return false

    }


回答6:

the easiest way to change to next text Field is this no need for long code

override func viewDidLoad() {
        super.viewDidLoad()

        emailTextField.delegate = self
        passwordTextField.delegate = self
    }


    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == emailTextField {
            passwordTextField.becomeFirstResponder()
        }else {
            passwordTextField.resignFirstResponder()
        }
            return true
    }


回答7:

Just use becomeFirstResponder() method of UIResponder class in your textFieldShouldReturn method. Every UIView objects are UIResponder's subclasses.

if self.emaillabel.isEqual(self.anotherTextField)
{
    self.anotherTextField.becomeFirstResponder()
}

You can find more information about becomeFirstResponder() method at Apple Doc's in here.



回答8:

Caleb's version in Swift 4.0

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let nextField = self.view.viewWithTag(textField.tag + 1) as? UITextField {
        nextField.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return false
}

P.S. textField.superview? not working for me



回答9:

An alternative method for purists who don't like using tags, and wants the UITextField delegate to be the cell to keep the components separated or uni-directional...

  1. Create a new protocol to link the Cell's and the TableViewController.

    protocol CellResponder {
      func setNextResponder(_ fromCell: UITableViewCell)
    }
    
  2. Add the protocol to your cell, where your TextField Delegate is also the cell (I do this in the Storyboard).

    class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
      var responder: CellResponder?
    
      func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        responder?.setNextResponder(self)
        return true
      }
    }
    
  3. Make your TableViewController conform to the CellResponder protocol (i.e. class MyTableViewController: UITableViewController, CellResponder) and implement the method as you wish. I.e. if you have different cell types then you could do this, likewise you could pass in the IndexPath, use a tag, etc.. Don't forget to set cell.responder = self in cellForRow..

    func setNextResponder(_ fromCell: UITableViewCell) {
      if fromCell is MyTableViewCell, let nextCell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? MySecondTableViewCell {
    
        nextCell.aTextField?.becomeFirstResponder()
    
      } ....
    }
    


回答10:

No any special, here is my currently using to change the textFiled. So the code in ViewController looks good :). #Swift4

final class SomeTextFiled: UITextField {

  public var actionKeyboardReturn: (() -> ())?

  override init(frame: CGRect) {
      super.init(frame: frame)
      super.delegate = self
  }

  required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      fatalError("init(coder:) has not been implemented")
  }

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      self.resignFirstResponder()
      actionKeyboardReturn?()
      return true
   }
}

extension SomeTextFiled: UITextFieldDelegate {}


class MyViewController : UIViewController {

    var tfName: SomeTextFiled!
    var tfEmail: SomeTextFiled!
    var tfPassword: SomeTextFiled!

    override func viewDidLoad() {
        super.viewDidLoad()
        tfName = SomeTextFiled(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        tfName.actionKeyboardReturn = { [weak self] in
            self?.tfEmail.becomeFirstResponder()
        }
        tfEmail = SomeTextFiled(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
        tfEmail.actionKeyboardReturn = { [weak self] in
            self?.tfPassword.becomeFirstResponder()
        }
        tfPassword = SomeTextFiled(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
        tfPassword.actionKeyboardReturn = {
            /// Do some further code
        }
    }
}