Search code examples
iosswiftuipickerview

Change UIPickerView values with toolbar button


I have a UITableView with 2 components for users to enter their height in feet and inches. I would like to add a button inside of the UIPicker toolbar that will give the option to change the input from 2 components (feet and inches) to only centimeters. I have added the toolbar button on the UIPickerView however I don't know what to do to make the change back and fourth from feet and inches to cm UIPickerView.

   let heightTF: UITextField = {
      let tf = UITextField()
      tf.placeholder = " Height"
      tf.translatesAutoresizingMaskIntoConstraints = false
      return tf
  }()


var pickerView: UIPickerView!

let feetList = Array(3...9)

let inchList = Array(0...11)

let numberOfComponents = 4


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

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if component == 0 {
        return feetList.count
    }else if component == 2 {
        return inchList.count
    }else {
        return 1
    }
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    if component == 0 {
        return "\(feetList[row])"
    }else if component == 1 {
        return "ft"
    }else if component == 2 {
        return "\(inchList[row])"
    }else {
        return "in"
    }
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    let feetIndex = pickerView.selectedRow(inComponent: 0)
    let inchIndex = pickerView.selectedRow(inComponent: 2)
    heightTF.text = "\(feetList[feetIndex])'\(inchList[inchIndex])''"
}
@objc func donePicker() {

    heightTF.resignFirstResponder()

}

 @objc func cmAction() {

    print("cm pressed")

}
func addDoneButtonOnKeyboard(){
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default
       let cmAction: UIBarButtonItem = UIBarButtonItem(title: "CM", style: .done, target: self, action: #selector(self.cmAction))
        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))

        let items = [cmAction, flexSpace, done]
        doneToolbar.items = items
        doneToolbar.sizeToFit()

        heightTF.inputAccessoryView = doneToolbar
   

    }

    @objc func doneButtonAction(){
        heightTF.resignFirstResponder()
    }
override func viewDidLoad() {
    addDoneButtonOnKeyboard()
    
    self.pickerView = UIPickerView(frame:CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 216))
    self.pickerView.delegate = self
    self.pickerView.dataSource = self
    heightTF.inputView = self.pickerView
    self.pickerView.backgroundColor = UIColor.white
    heightTF.inputView = self.pickerView
   
    
   
   }

Solution

  • First you need to save the type of unit you want to use :

    enum UnitType {
        case feetInches
        case cm
    }
    var unitType = UnitType.feetInches
    

    Then in the action you change the value between feetInches and cm, and reload all components of the pickerView.

    @objc func cmAction() {
        switch unitType {
        case .feetInches:
             // add code to convert from feet/inches to cm
             unitType = .cm
            self.pickerView.reloadAllComponents()
            // add code to select cm row
        case .cm:
             // add code to convert from cm to feet/inches
            unitType = .feetInches
            self.pickerView.reloadAllComponents()
            // add code to select feet and inches rows
        }
    }
    

    In each pickerView delegate method you set up according to the value of unitType. eg :

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        switch unitType {
        case .feetInches:
            return numberOfComponents /* =4 */
        case .cm:
            return 2 /* (number of cm) and cm */
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch unitType {
        case .feetInches:
            if component == 0 {
                return "\(feetList[row])"
            }else if component == 1 {
                return "ft"
            }else if component == 2 {
                return "\(inchList[row])"
            }else {
            return "in"
            }
        case .cm: 
            if component == 0 {
                return "\(cmList[row])"
            }else if component == 1 {
                return "cm"
            }
        }
    }
    ...