1

I have a SignUp Form which includes a number of UITextfields and UIButton. I have set up UITextfield delegates so that the when user starts editing on a UITextfield and presses the return key it goes to the next UITextfield.

SignUp Form

DoB, ISD Code, Gender and Nationality are UIButtons which have IBActions, and rest of them are UITextfields

Is it possible to initiate a IBAction of a UIButton on pressing the return key from a Textfield. So that the user can sequentially add the necessary data to the signup form.

What i have done so far ..

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{

    if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField
    {
        nextField.becomeFirstResponder()
    }
    else {
        // Not found, so remove keyboard.
        signupScrollView .setContentOffset(CGPoint( x: 0, y: 0), animated: true)
        textField.resignFirstResponder()
        return true
    }
    // Do not add a line break
    return false
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    signupScrollView .setContentOffset(CGPoint( x: 0, y: textField.center.y-200), animated: true)

}
Jayesh Thanki
  • 2,037
  • 2
  • 23
  • 32
alpha47
  • 305
  • 3
  • 17

1 Answers1

1

Assuming your textFields and buttons have a common sequence of tags, you can basically do something like the following:

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

    let nextView = textField.superview?.viewWithTag(textField.tag + 1)

    if let nextTextField = nextView as? UITextField {
        //next view is a textField so make next textField first responder
        nextTextField.becomeFirstResponder()
    }
    //just this extra case is required
    else if let nextButton = nextView as? UIButton {
        //next view is a button so call it's associated action
        //(assuming your button's @IBAction is on the Touch Up Inside event)
        nextButton.sendActions(for: .touchUpInside)

        /*
         a button's action will be performed so if you want to 
         perform the return action on the textField then either
         return true/false. Decide that as per your requirement
         */
        return true
    }
    else {
        //...
    }
    
    //...
}

The above logic is enough to answer your question but works only when the user is on a textField and has tapped on the keyboard's Return button.

Now... the thing is that on the end of a button actions, if you want to continue to the next view; textField or button, you can either1 explicitly code to make the next view active.

Example:

  • After ISD Code is done you could make the mobile textField as first responder
  • After Gender is done, you could call the button action for Nationality

Or2...

We can modify the solution to handle textField as well as buttons alike with a common helper function, that we will call goNext(from:) to be implemented in textFieldShouldReturn(_:) as well as after the button is to complete it's intended logic flow.

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let nextView = goNext(from: textField)
    
    if let nextTextField = nextView as? UITextField {
        //Next field was a textField so keyboard should stay
        return false
    }
    
    textField.resignFirstResponder()
    return true
}

@discardableResult func goNext(from sender: UIView) -> UIView? {
    let nextView = sender.superview?.viewWithTag(sender.tag + 1)
    print(nextView?.tag ?? "No view with tag \(sender.tag + 1)")
    
    if let nextTextField = nextView as? UITextField {
        nextTextField.becomeFirstResponder()
    }
    else if let nextButton = nextView as? UIButton {
        nextButton.sendActions(for: .touchUpInside)
    }
    else {
        print("Done")
        signupScrollView.setContentOffset(CGPoint(x: 0, y: 0), 
                                          animated: true)
        sender.resignFirstResponder()
    }

    return nextView
}

Now for the button part, you need to perform goNext(from: button) whenever the associated button has completed it's logic.

Example:

  • User has successfully selected Date of Birth: You should then be calling

    goNext(from: dobButton)

Community
  • 1
  • 1
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • @alpha47 sure, let me know :) – staticVoidMan Apr 14 '18 at 08:21
  • getting an error at `else if let nextButton = nextView as? UIButton` " Use of unresolved identifier 'nextView' " – alpha47 Apr 14 '18 at 08:34
  • 1
    check `nextView`. you should have `let nextView = textField.superview?.viewWithTag(textField.tag + 1)` before you do the `if let` – staticVoidMan Apr 14 '18 at 08:36
  • that did the trick, i had to add `isdButton.sendAction(for: .touchUpInside)` at the end of DoB's Action. and to initiate `Mobile` textfield, made it the first responder at the end of `isdButton`'s Action.. – alpha47 Apr 14 '18 at 09:02
  • @alpha47 awesome! but you should not call `goNext(from:)` immediatey at the end of `DoB` button's action but rather after the user has selected the date of birth. – staticVoidMan Apr 14 '18 at 09:06
  • @alpha47 Check updated answer. Better case handling for you. Anyways... glad to help and... happy coding :) – staticVoidMan Apr 14 '18 at 09:10