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
}
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"
}
}
}
...