Search code examples
iosswiftuitextfielduipickerview

pickerView didSelectRow is inputting into the wrong UITextField


I am trying to follow the following solution to having multiple UIPickerViews on the one UIViewController. They suggest that a tag for each of the UITextfield which I have done and able to implement the number of rows, title for row and number of components. However, I have reached a stumbling block when implementing the did select row. When I select the UITextField it highlights another UITextfield. Below is the code I have so far. class DriverViewController: UIViewController {

var selectedTrack: String?

var firstDriver: String?

var secondDriver: String?

var thirdDriver: String?
let  tracks = ["Melbourne", "Manama", "Shanghai", "Baku",
               "Barcelona", "Monaco", "Montreal","Le Castellet","Spielberg",
               "Silverstone","Hockenheim","Budapest","Francorchamps","Monza","Singapore","Sochi","Suzuka","Austin","Interlagos","Abu Dhabi"]
let drivers = ["Lewis Hamilton","Antonio Giovinazzi","Kimi Raikkonen","Charles Leclerc","Sebastian Vettel","Romain Grosjean","Kevin Magnussen","Lando Norris",
               "Carlos Sainz","Valtteri Bottas","Sergio Perez","Lance Stroll","Pierre Gasly","Max Verstappen","Nico Hulkenberg","Daniel Ricciardo","Alexander Albon","Daniil Kvyat","Robert Kubica","George Russell"]
@IBOutlet weak var TrackTextField: UITextField!


@IBOutlet weak var firstTextField: UITextField!

@IBOutlet weak var secondTextField: UITextField!


@IBOutlet weak var thirdTextField: UITextField!


override func viewDidLoad() {
    super.viewDidLoad()


    createTrackPicker()
    createDriverPicker()
    createToolBar()
    // Do any additional setup after loading the view.
}

func createTrackPicker() {
    let trackPicker = UIPickerView()
    trackPicker.tag = 0
    trackPicker.delegate = self
    TrackTextField.inputView = trackPicker
}

func createDriverPicker() {
    let driverPicker = UIPickerView()
    driverPicker.tag = 1
    driverPicker.tag = 2
    driverPicker.tag = 3
    driverPicker.delegate = self
    firstTextField.inputView = driverPicker
    secondTextField.inputView = driverPicker
    thirdTextField.inputView = driverPicker
}

func createToolBar() {

    let toolBar = UIToolbar()
    toolBar.sizeToFit()
    let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ViewController.dismissKeyboard))
    toolBar.setItems([doneButton], animated: false)
    toolBar.isUserInteractionEnabled = true
    TrackTextField.inputAccessoryView = toolBar
    firstTextField.inputAccessoryView = toolBar
    secondTextField.inputAccessoryView = toolBar
    thirdTextField.inputAccessoryView = toolBar

}
@objc func dismissKeyboard() {
    view.endEditing(true)
}
/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destination.
    // Pass the selected object to the new view controller.
}
 */

}

 extension DriverViewController: UIPickerViewDelegate, UIPickerViewDataSource {
 func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if pickerView.tag == 0 {
        return tracks.count
    } else {
        return drivers.count
    }
}


func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    if pickerView.tag == 0 {
        return "\(tracks[row])"
    } else {
        return "\(drivers[row])"
    }
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if pickerView.tag == 0 {
        selectedTrack = tracks[row]
        TrackTextField.text = selectedTrack
    } else if pickerView.tag == 1 {
        firstDriver = drivers[row]
        firstTextField.text = firstDriver
    } else if pickerView.tag == 2 {
        secondDriver = drivers[row]
        secondTextField.text = secondDriver
    } else if pickerView.tag == 3 {
        thirdDriver = drivers[row]
        thirdTextField.text = thirdDriver
    }
  }
}

This is how it looks on the screen.Simulator Screenshot


Solution

  • Look at your function:

    func createDriverPicker() {
        let driverPicker = UIPickerView()
        driverPicker.tag = 1
        driverPicker.tag = 2
        driverPicker.tag = 3
        driverPicker.delegate = self
        firstTextField.inputView = driverPicker
        secondTextField.inputView = driverPicker
        thirdTextField.inputView = driverPicker
    }
    

    Think about what value the tag property has after this code is run keeping in mind that it can only have one value.

    You either need to update the picker view's tag property each time a text field begins editing, or you should abandon the use of the tag and simply check which text field is currently the first responder. See UIPickerView for each text field with different arrays (Swift/Firebase) for an example of how this is done.