Search code examples
iosswiftuipickerview

Unable to use two UIPickerViews on one viewcontroller


I currently have a view controller with 3 text fields:

customerTextField

manufacturerTextField

modelTextField

When selecting manufacturerTextField I need the UIPicker associated with https://www.example.com/example/Manufacturer.php to appear.

This UIPicker by design has two columns that are populated using JSON data. When making the selection the UIPicker populates both manufacturerTextField and modelTextField

When the user selects customerTextField I would like the UIPickerView to show the data from https://www.example.com/example/customer.php

This should only be a single column selection.

UPDATED ISSUE:

The following is what I currently have, for some reason when selecting customerTextField the UIPicker with two columns comes up with manufacturerTextField data.

    import UIKit

class CreateRMA_ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate {



        @IBOutlet weak var customerTextField: UITextField!
        @IBOutlet weak var manufacturerTextField: UITextField!
        @IBOutlet weak var modelTextField: UITextField!

        var selectedTextField = UITextField()

    struct Category {
        var name: String
        var items: [String]
    }
    var allCategories = [Category]()
    var selectedCategory:Category?
    var selectedItem: String?

    var pickerView: UIPickerView!
    var values: [AnyObject] = []

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    selectedTextField = textField
    pickerView.isHidden = false
    return true
}

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        if selectedTextField == customerTextField {
            return 1
        } else if selectedTextField == manufacturerTextField {
            return selectedCategory == nil ? 1 : 2
        } else {//modelTextField
            return 2
        }
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if selectedTextField == customerTextField {
            return values.count
        } else if selectedTextField == manufacturerTextField {
            return component == 0 ? allCategories.count : selectedCategory?.items.count ?? 0
        } else {//modelTextField
            return selectedCategory?.items.count ?? 0
        }
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if selectedTextField == customerTextField {
            return values[row] as? String
        } else if selectedTextField == manufacturerTextField {
            if component == 0 {
                return allCategories[row].name
            } else {
                return selectedCategory?.items[row]
            }
        } else {//modelTextField
            return selectedCategory?.items[row]
        }
    }


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

        if component == 0 {
            selectedCategory = allCategories[row]
            manufacturerTextField.text = allCategories[row].name
            pickerView.reloadAllComponents()
        } else {
            selectedItem = selectedCategory?.items[row]
            modelTextField.text = selectedCategory?.items[row]
        }
    }







    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }


        override func viewDidLoad() {
            super.viewDidLoad()

            pickerView = UIPickerView()
            pickerView.dataSource = self
            pickerView.delegate = self
            manufacturerTextField.inputView = pickerView






            //get the values from sql/Json
            let url = NSURL(string: "https://www.example.com/test/service.php")

            let data = NSData(contentsOf: url! as URL)
            var tmpValues = try! JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
            tmpValues = tmpValues.reversed() as NSArray
            reloadInputViews()


            for candidate in tmpValues {
                if let cdict = candidate as? NSDictionary {

                    //fullName is the column name in sql/json
                    let names = cdict["customer"]
                    self.values.append(names! as AnyObject)


                }
            }

            if let url = URL(string: "https://www.example.com/test/Make_Model.php"),
                let data = try? Data(contentsOf: url),
                let tmpValues = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String:String]] {
                let tempCategories = tmpValues?.reduce(into: [String:[String]](), { (dict, value) in
                    if let manufacturer = value["manufacturer"], let model = value["model"] {
                        dict[manufacturer, default:[]].append(model)
                    }
                })
                for category in (tempCategories ?? [:]) {
                    allCategories.append(Category(name: category.key, items: category.value))
                }
                pickerView.reloadAllComponents()
            }
    }



}

Solution

  • When you have multiple text fields having the same picker view as input view you need to keep a reference to the currently selected text field

    @IBOutlet weak var customerTextField: UITextField!
    @IBOutlet weak var manufacturerTextField: UITextField!
    @IBOutlet weak var modelTextField: UITextField!
    var selectedTextField = UITextField()
    

    Assign selected textfield to this temp textfield in textFieldShouldBeginEditing

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        selectedTextField = textField
        pickerView.reloadAllComponents()
        pickerView.isHidden = false
        return true
    }
    

    And check which textfield is selected in picker view datasource and delegate methods and use appropriate data source.

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        if selectedTextField == customerTextField {
            return 1
        } else if selectedTextField == manufacturerTextField {
            return selectedCategory == nil ? 1 : 2
        } else {//modelTextField
            return 2
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if selectedTextField == customerTextField {
            return values.count
        } else if selectedTextField == manufacturerTextField {
            return component == 0 ? allCategories.count : selectedCategory?.items.count ?? 0
        } else {//modelTextField
            return selectedCategory?.items.count ?? 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if selectedTextField == customerTextField {
            return values[row] as? String
        } else if selectedTextField == manufacturerTextField {
            if component == 0 {
                return allCategories[row].name
            } else {
                return selectedCategory?.items[row]
            }
        } else {//modelTextField
            return selectedCategory?.items[row]
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        if selectedTextField == customerTextField {
            customerTextField.text = values[row] as? String
        } else if selectedTextField == manufacturerTextField {
            if component == 0 {
                selectedCategory = allCategories[row]
                manufacturerTextField.text = allCategories[row].name
                pickerView.reloadAllComponents()
            } else {
                selectedItem = selectedCategory?.items[row]
                modelTextField.text = selectedCategory?.items[row]
            }
        } else {//modelTextField
            modelTextField.text = selectedCategory?.items[row]
        }
    }