LaVOZs

The World’s Largest Online Community for Developers

'; ios - PickerView for multiple text fields is just showing one Array - LavOzs.Com

I have a weird problem but I guess you guys can show me the mistake pretty easy. I am using a picker view for multiple text fields. But it only shows the "last array" for every text field and pushes on top of everything the selected row in the last text field. Therefore it seems that every text field controls only the last text field.

Here is the involved code, hope you guys can help me:

class SignUpViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {




    //Mark: Properties


    @IBOutlet weak var genderPicker: UITextField!
    @IBOutlet weak var branchePicker: UITextField!
    @IBOutlet weak var countryPicker: UITextField!




    // Picker View Arrays
    let genders = ["male", "female", "non-binary"]
    let branches = ["Advertising", "Architecture", "Design: Product", "Design: Graphic", "Design: Fashion", "Design: Others", "Film/ Video & TV", "IT", "Museums & Galleries", "Music", "Photography", "Performing & Visual Arts", "Radio", "Others"]
    let countries = ["Austria", "Australia", "USA", "Germany"]

    // Picker View
    var pickerViewSignUp = UIPickerView()



    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.





        // Pickers

        pickerViewSignUp.delegate = self
        pickerViewSignUp.dataSource = self


        // Delegates
        genderPicker.textAlignment = .center
        genderPicker.inputView = pickerViewSignUp
        genderPicker.placeholder = "Select Gender"

        branchePicker.textAlignment = .center
        branchePicker.inputView = pickerViewSignUp
        branchePicker.placeholder = "Select Branch"

        countryPicker.textAlignment = .center
        countryPicker.inputView = pickerViewSignUp
        countryPicker.placeholder = "Select Country"



    }


    // Mark: PickerViews
            // List of the SignUp used Drop Down Items

            // TextField delegate

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

        pickerViewSignUp.reloadAllComponents()

             return true
         }


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

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

        if pickerViewSignUp == genderPicker {
            return genders.count

        }   else if pickerViewSignUp == branchePicker {
            return branches.count

        } else {return countries.count}

    }


    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if pickerViewSignUp == genderPicker {
            return genders[row]
        } else if  pickerViewSignUp == branchePicker {
            return branches[row] } else {return countries[row]}
    }


    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)  {

        if pickerViewSignUp == genderPicker {
            genderPicker.text = genders[row]
        } else if pickerViewSignUp == branchePicker {
            branchePicker.text = branches[row]
        } else {countryPicker.text = countries[row]}
    }

}

This is my solution... use an enum to track the selected state and add UITextFieldDelegates:

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {


//Mark: Properties
@IBOutlet weak var genderPicker: UITextField!
@IBOutlet weak var branchePicker: UITextField!
@IBOutlet weak var countryPicker: UITextField!

enum TextFieldType {
    case gender
    case branche
    case country
    case none
}

// Picker View Arrays
let genders = ["male", "female", "non-binary"]
let branches = ["Advertising", "Architecture", "Design: Product", "Design: Graphic", "Design: Fashion", "Design: Others", "Film/ Video & TV", "IT", "Museums & Galleries", "Music", "Photography", "Performing & Visual Arts", "Radio", "Others"]
let countries = ["Austria", "Australia", "USA", "Germany"]

// Picker View
var pickerViewSignUp = UIPickerView()
var selectedPikerType =  TextFieldType.none

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.


    // Pickers

    pickerViewSignUp.delegate = self
    pickerViewSignUp.dataSource = self


    // Delegates
    genderPicker.textAlignment = .center
    genderPicker.inputView = pickerViewSignUp
    genderPicker.placeholder = "Select Gender"
    genderPicker.delegate = self

    branchePicker.textAlignment = .center
    branchePicker.inputView = pickerViewSignUp
    branchePicker.placeholder = "Select Branch"
    branchePicker.delegate = self

    countryPicker.textAlignment = .center
    countryPicker.inputView = pickerViewSignUp
    countryPicker.placeholder = "Select Country"
    countryPicker.delegate = self
}


// Mark: PickerViews
        // List of the SignUp used Drop Down Items

        // TextField delegate


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

    switch textField {
    case genderPicker: selectedPikerType    = .gender
    case branchePicker: selectedPikerType   = .branche
    case countryPicker: selectedPikerType   = .country
    default: selectedPikerType              = .none
    }


    pickerViewSignUp.reloadAllComponents()

    return true
}


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

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

    switch selectedPikerType {
    case .branche   : return branches.count
    case .country   : return countries.count
    case .gender    : return genders.count
    case .none      : return 0
    }

}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

    switch selectedPikerType {
    case .branche   : return branches[row]
    case .country   : return countries[row]
    case .gender    : return genders[row]
    case .none      : return nil
    }
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)  {

    switch selectedPikerType {
    case .branche   : branchePicker.text = branches[row]
    case .country   : countryPicker.text = countries[row]
    case .gender    : genderPicker.text = genders[row]
    case .none      : break
    }
}

}

I'd also suggest you a better naming of the variables... If the object is a textfield use the prefix "txt" ... so txtGender and so on. It is way clearer. Use also extensions to split datasources and delegates it makes it all more readable. :)

You can write an extension like this:

extension ViewController: UITextFieldDelegate {

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

       switch textField {
       case genderPicker: selectedPikerType    = .gender
       case branchePicker: selectedPikerType   = .branche
       case countryPicker: selectedPikerType   = .country
       default: selectedPikerType              = .none
       }


       pickerViewSignUp.reloadAllComponents()

       return true
   }

}

Have a global textField variable in your class to get the instance of textField you are editing and assign the value when editing.

In the pickerView delegate and datasource methods do the comparison between the current textField and the rest of the textField elements. It should work.

Below is the code for your reference:

class SignupViewController {

var currentTextfield: UITextField?

// Mark: PickerViews
// List of the SignUp used Drop Down Items

// TextField delegate

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    currentTextfield = textField
    pickerViewSignUp.reloadAllComponents()
    return true
}


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

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    switch currentTextfield {
    case genderPicker:
        return genders.count
    case branchePicker:
        return branches.count
    default
        return countries.count
    }
}

}

Related