6

I have six textfields. Now if all my textfield are filled and tap on any textfield the it should always put focus on sixth textfield & show the keyboard. I have tried below code but it does not show keyboard and only put focus when I tap on sixth textfield. please tell me what is the issue with this ?

func textFieldDidBeginEditing(_ textField: UITextField) {
     textField.inputAccessoryView = emptyView
        if let textOneLength = textFieldOne.text?.length ,let textTwoLength = textFieldTwo.text?.length ,let textThreeLength = textFieldThree.text?.length , let textFourLength = textFieldFour.text?.length,let textFiveLength = textFieldFive.text?.length , let textSixLength = textFieldSix.text?.length {
            if (textOneLength > 0) && (textTwoLength > 0) && (textThreeLength > 0) && (textFourLength > 0) && (textFiveLength > 0) && (textSixLength > 0) {
                self.textFieldSix.becomeFirstResponder()
            } else if (textOneLength <= 0) && (textTwoLength <= 0) && (textThreeLength <= 0) && (textFourLength <= 0) && (textFiveLength <= 0) && (textSixLength <= 0){
                self.textFieldOne.becomeFirstResponder()
            }
        }
}
vp2698
  • 1,783
  • 26
  • 28
TechChain
  • 8,404
  • 29
  • 103
  • 228

8 Answers8

4

I think accepted answer is hack. Other thing that we can do is detect touchDown on UITextField, check if last textField should be in focus and do becomeFirstResponder() on it. Next thing, we should disallow focus other textFields if last should be in focus. We can do that in textFieldShouldBeginEditing method.

Here example of ViewController. Just connect 3 textFields and all should work as expected (Swift 4):

class ViewController: UIViewController {

    @IBOutlet weak var firstTextField: UITextField!
    @IBOutlet weak var secondTextField: UITextField!
    @IBOutlet weak var thirdTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        firstTextField.delegate = self
        secondTextField.delegate = self
        thirdTextField.delegate = self

        firstTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
        secondTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
        thirdTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
    }

    @IBAction private func textFieldTouch(_ sender: UITextField) {
        if shouldFocusOnLastTextField {
            thirdTextField.becomeFirstResponder()
        }
    }

    private var shouldFocusOnLastTextField: Bool {
        return firstTextField.text?.isEmpty == false && secondTextField.text?.isEmpty == false  && thirdTextField.text?.isEmpty == false
    }

}

extension ViewController: UITextFieldDelegate {

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        guard shouldFocusOnLastTextField else { return true }
        return textField == thirdTextField
    }

}

Other, more simple way to achieve that check the textField that is going to be focused:

extension ViewController: UITextFieldDelegate {

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        guard firstTextField.text?.isEmpty == false &&
            secondTextField.text?.isEmpty == false  &&
            thirdTextField.text?.isEmpty == false &&
            textField != thirdTextField else { return true }

        thirdTextField.becomeFirstResponder()
        return false
    }

}
pacification
  • 5,838
  • 4
  • 29
  • 51
1

The problem with your implementation is that you are trying to assign the first responder when it was already assign to another textField.
The following code should do the trick:

extension TestViewController: UITextFieldDelegate {

func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.inputAccessoryView = UIView()
}

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    if let textOneLength = textFieldOne.text?.count ,let textTwoLength = textFieldTwo.text?.count ,let textThreeLength = textFieldThree.text?.count , let textFourLength = textFieldFour.text?.count,let textFiveLength = textFieldFive.text?.count , let textSixLength = textFieldSix.text?.count {
        if (textOneLength > 0) && (textTwoLength > 0) && (textThreeLength > 0) && (textFourLength > 0) && (textFiveLength > 0) && (textSixLength > 0) {

            ///Check if the sixth textField was selected to avoid infinite recursion
            if textFieldSix != textField {
                self.textFieldSix.becomeFirstResponder()
                return false

            }
        } else if (textOneLength <= 0) && (textTwoLength <= 0) && (textThreeLength <= 0) && (textFourLength <= 0) && (textFiveLength <= 0) && (textSixLength <= 0){

            ///Check if the first textField was selected to avoid infinite recursion
            if textFieldOne != textField {
                self.textFieldOne.becomeFirstResponder()
                return false
            }
        }
    }
    return true
}

}
weissja19
  • 535
  • 4
  • 11
0

It should be work. Are you sure that the simulator has the property to show the keywoard enable? You can change that property with the keys: Command + Shift + k

  • Are you sure that: 1 - ViewController implement the UITextFieldDelegate "class NAME: UIViewcontroller, UITextFieldDelegate" 2 - all textFields have a delegate assigned textFieldOne.delegate = self textFieldTwo.delegate = self textFieldThree.delegate = self textFieldFour.delegate = self textFieldFive.delegate = self textFieldSix.delegate = self – Lucas Pelizza Mar 26 '18 at 13:30
  • It's all there what you have written but I don not understand what is the problem – TechChain Mar 27 '18 at 09:55
  • please, tell me what is your version of swift, so I will do an example for you and I will send it. – Lucas Pelizza Mar 28 '18 at 12:30
0

I know it is strange for me as well but delaying the focus on text field worked for me.

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                self.textFieldOne.becomeFirstResponder()
            }

I added above code in textFieldDidBeginEdting & it worked like magic.

TechChain
  • 8,404
  • 29
  • 103
  • 228
  • Hi, @Techiee. You answer is just a hack. Please, see my [answer](https://stackoverflow.com/a/49511309/2463616). – pacification Mar 27 '18 at 11:08
  • I think hack saved my lot of time & saved me from writing lot of code. I know my approach is not good.I am going to try your answer – TechChain Mar 27 '18 at 11:11
  • Technically, in future you can handle bag or even crash because of the delay. Again, check my answer. It's pretty compact and should work ;) – pacification Mar 27 '18 at 11:13
  • Do you actually need the delay? In these situations I've just used DispatchQueue.main.async(). To me this is a valid approach to delay the change of focus request until after the textFieldDidBeginEditing has completed, which itself is trying to affect the focus – Dale Mar 28 '18 at 03:44
0

In this case, you'll want to reject attempted edits before they happened; when we wish to reject an attempted edit we will also need to set the sixth textfield as the new first responder.

extension MyViewController: UITextFieldDelegate {
  func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    if textFieldOne.text?.isEmpty == false && textFieldTwo.text?.isEmpty == false  && textFieldThree.text?.isEmpty == false && textFieldFour.text?.isEmpty == false && textFieldFive.text?.isEmpty == false && textFieldSix.text?.isEmpty == false  {
      if textField != textFieldSix {
        textFieldSix.becomeFirstResponder()
        return false
      } else {
        return true
      }
    } else {
      return true
    }
  }
}
jnblanchard
  • 1,182
  • 12
  • 12
0

1 Set UITextfielddelegate in viewcontroller

2 Set self delegate to every textfield

3 add tag value for every textfield

4 add textfield.becomeFirstResponder()

5 check if condition using tag for take specify textfield value

Gowtham Sooryaraj
  • 3,639
  • 3
  • 13
  • 22
0

Reference to this answer https://stackoverflow.com/a/27098244/4990506

A responder object only becomes the first responder if the current responder can resign first-responder status (canResignFirstResponder) and the new responder can become first responder.

You may call this method to make a responder object such as a view the first responder. However, you should only call it on that view if it is part of a view hierarchy. If the view’s window property holds a UIWindow object, it has been installed in a view hierarchy; if it returns nil, the view is detached from any hierarchy.

First set delegate to all field

self.textFieldOne.delegate = self
self.textFieldTwo.delegate = self
self.textFieldThree.delegate = self
self.textFieldFour.delegate = self
self.textFieldFive.delegate = self
self.textFieldSix.delegate = self

And then delegate

extension ViewController : UITextFieldDelegate{
    func textFieldDidBeginEditing(_ textField: UITextField) {
        if self.textFieldOne.hasText ,self.textFieldTwo.hasText ,self.textFieldThree.hasText ,self.textFieldFour.hasText ,self.textFieldFive.hasText ,self.textFieldSix.hasText  {
            textFieldSix.perform(
                #selector(becomeFirstResponder),
                with: nil,
                afterDelay: 0.1
            )
        }else if !self.textFieldOne.hasText ,!self.textFieldTwo.hasText ,!self.textFieldThree.hasText ,!self.textFieldFour.hasText ,!self.textFieldFive.hasText ,!self.textFieldSix.hasText {
            textFieldOne.perform(
                #selector(becomeFirstResponder),
                with: nil,
                afterDelay: 0.1
            )
        }
    }
}
vp2698
  • 1,783
  • 26
  • 28
-1

To check any textfield use this code

for view in self.view.subviews {
    if let textField = view as? UITextField {
        print(textField.text!)
    }
}

** you can also identify a textfiled by using this -

if let txtFieldINeed = self.view.viewWithTag(99) as? UITextField {
    print(txtFieldINeed.text!)
}

** then use -- txtFieldINeed.becomeFirstResponder()

** Make sure to turn on this options -- * iOS Simulator -> Hardware -> Keyboard * Uncheck "Connect Hardware Keyboard"

Rahul Singha Roy
  • 548
  • 1
  • 3
  • 13