Search code examples
iosswiftuitextfieldseguecontainer-view

How to detect focused UITextField in Container view from Parent View Controller


I have a container view with multiple text boxes on it. I also have a button in Parent View controller(custom keypad). What I'm trying to do is select text box first & when I tap on the button I wanted some value to be populated to that last selected/focused textbox. How can I do that? any alternative ways are welcome too. (I am having multiple container-views in the original code and try to use one keypad for all the views)

storyboard

class MainViewController: UIViewController {
    var weightVC : WeightViewController!
    var focusedElement : UITextField

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if (segue.identifier == "weight") {
            weightVC = segue.destination as? WeightViewController
        }
    }

    @IBAction func button1Clicked(_ sender: Any) {

        if weightVC != nil {
            weightVC.sampleTextBox1.text = "1"
            //I want this sampleTextBox1 to be dynamic like weightVC.focusedInput = "1"
        }

    }
}

extension MainViewController:ChildToParentProtocol {
   func setFocusedElement(with value: UITextField){
      focusedElement = value
   }
}

Container View Controller


protocol ChildToParentProtocol: class {
    func setFocusedElement(with value:UITextField)
}

class WeightViewController: UIViewController {

    weak var delegate:  ChildToParentProtocol? = nil

    @IBOutlet weak var sampleTextBox1: UITextField!
    @IBOutlet weak var sampleTextBox2: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // sampleTextBox1 Editing Did Begin event
    @IBAction func editBeginSampleText1(_ sender: Any) {
        print("edit begin")
        delegate?.setFocusedElement(with: sampleTextBox1)
    }

}

In other words, I simply want to keep a reference to last focused UITextFild when a button is tapped. Hope my requirement is clear enough. Please guide me if there is a way to achieve this.

Thanks


Solution

  • If I understood your question correctly you can keep track on which UITextField is tapped by using it's tag. And you can use UITextFieldDelegate to get the selected UITextField tag.

    Consider the below code for WeightViewController

    protocol ChildToParentProtocol: class {
        //Changed value to Int for passing the tag.
        func setFocusedElement(with value: Int)
    }
    
    import UIKit
    
    class WeightViewController: UIViewController {
    
        @IBOutlet weak var tf1: UITextField!
        @IBOutlet weak var tf2: UITextField!
    
        var selectedTFTag = 0
        weak var delegate: ChildToParentProtocol? = nil
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //Assign delegate and tags to your TF
            tf1.delegate = self
            tf2.delegate = self
    
            tf1.tag = 1
            tf2.tag = 2
        }
    }
    
    extension WeightViewController: UITextFieldDelegate {
        func textFieldDidBeginEditing(_ textField: UITextField) {
            //Get the selected TF tag
            selectedTFTag = textField.tag
            //Pass tag to parent view
            delegate?.setFocusedElement(with: selectedTFTag)
        }
    }
    

    Now in your parent view ViewController you need to make some modification. I have added comments where I made changes to achieve your requirement.

    import UIKit
    
    //You need to confirm your ChildToParentProtocol with your UIViewController
    class ViewController: UIViewController, ChildToParentProtocol {
    
        var selectedTFTag = 0
        var weightVC : WeightViewController!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "weight" {
                weightVC = segue.destination as? WeightViewController
                //You need to pass delegate to containerview to make it working.
                weightVC.delegate = self
            }
        }
    
        @IBAction func btn1Tapped(_ sender: Any) {
    
            //According to selected Tag perform your action
            if selectedTFTag > 0 {
                switch selectedTFTag {
                case 1:
                    //set up first UITextField
                    weightVC.tf1.text = "First textfield was selected"
                    print("1")
                case 2:
                    //set up second UITextField
                    weightVC.tf2.text = "Second textfield was selected"
                default:
                    break
                }
            }
        }
    
        @IBAction func btn2Tapped(_ sender: Any) {
    
            //According to selected Tag perform your action
            if selectedTFTag > 0 {
                switch selectedTFTag {
                case 1:
                    //set up first UITextField
                    weightVC.tf1.text = "First textfield was selected"
                    print("1")
                case 2:
                    //set up second UITextField
                    weightVC.tf2.text = "Second textfield was selected"
                default:
                    break
                }
            }
        }
    
        func setFocusedElement(with value: Int) {
            //Get selected TF tag with delegate
            selectedTFTag = value
        }
    }
    

    You can check THIS demo project for more info.