In this tutorial, we’ll be discussing UIPickerView component in our iOS Application.
UIPickerView
UIPickerView is a UI element which is used to make a selection from multiple choices displayed in a vertical wheel. It is quite similar to what a dropdown is in Android or Web UI.
A wheel is known as a component in a UIPickerView.
A single UIPickerView can host one or more components.
Every component can contain independent data and can be selected and changed.
Typically, an array is used to display data in the rows of a UIPickerView component.
To show data in the UIPickerView you must adopt the protocol, UIPickerViewDataSource in your application and implement its required methods.
You must adopt the protocol, UIPickerViewDelegate in order to display the rows and also to allow making user selections.
If you don’t use the latter protocol in your ViewController, you might end up with something like this :
Following are the four most important functions:
1 2 3 4 5 6 |
func numberOfComponents(in pickerView: UIPickerView) -> Int func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) |
titleForRow
is used to display the data in the UIPickerView component(s).didSelectRow
gets called whenever any of the UIPickerView rows is selected.
Before we get down to the complex stuff in a later section, let’s implement a simple UIPicker in our XCode Single View Application Project.
Project Storyboard
We’ve added a UIPickerView, a UILabel and a UITextField. We’ll display the selection from the UIPickerView in the UILabel. Later we’ll create another UIPickerView at the bottom to choose the text for the UITextField.
Code
The code for the ViewController.swift is given below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import UIKit class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate { @IBOutlet weak var myTextField: UITextField! @IBOutlet weak var myLabel: UILabel! @IBOutlet weak var topPickerView: UIPickerView! var arrayOf100 = Array(0...100) var arrayOf2 = Array(1...2) var labelString = "" override func viewDidLoad() { super.viewDidLoad() topPickerView.delegate = self topPickerView.delegate?.pickerView?(topPickerView, didSelectRow: 0, inComponent: 0) topPickerView.delegate?.pickerView?(topPickerView, didSelectRow: 0, inComponent: 1) } func numberOfComponents(in pickerView: UIPickerView) -> Int { return 2 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if component == 0{ return arrayOf2.count } else{ return arrayOf100.count } } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { if component == 0 { return String(arrayOf2[row]) } else{ return String(arrayOf100[row]) } } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { let digitsValue = arrayOf2[topPickerView.selectedRow(inComponent: 0)] let decimalValue = arrayOf100[topPickerView.selectedRow(inComponent: 1)] myLabel.text = "Value is (digitsValue).(decimalValue)" if component == 0 { print(String(arrayOf2[row])) } else{ print(String(arrayOf100[row])) } } } |
topPickerView.delegate = self
is the most important line. In a way it activates the Protocols on the UIPickerView instance.
We’re returning 2 components and we’ve populated each of them with a different array.
didSelectRow
gets called whenever any of the rows are selected. BUT, it won’t call all of the components in the selection. For that, we use the selectedRow(inComponent:)
to get the values from the selected rows of the components. These are then appended and displayed in a string.
Since the initial state doesn’t trigger didSelectRow
, we call the method on both of our components in the viewDidLoad
method.
The output when the above application was run on the iOS Simulator is:
Now let’s create another UIPickerView which would open instead of the Keyboard.
UIPickerView in place of Keyboard
To add a UIPickerView in place of keyboard we just need to set the inputView property on the UITextField to the UIPickerView.
1 2 3 4 5 6 7 8 9 |
func createAnotherPicker() { let anotherPicker = UIPickerView() anotherPicker.delegate = self anotherPicker.delegate?.pickerView?(anotherPicker, didSelectRow: 0, inComponent: 0) myTextField.inputView = anotherPicker } |
Following is the updated code of the ViewController.swift. All we need to do in the delegate methods is to check for the type of the UIPickerView instance in order to use both the UIPickerViews
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
import UIKit class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate { @IBOutlet weak var myTextField: UITextField! @IBOutlet weak var myLabel: UILabel! @IBOutlet weak var topPickerView: UIPickerView! var arrayOf100 = Array(0...100) var arrayOf2 = Array(1...2) var labelString = "" let anotherPicker = UIPickerView() var arrayOfCountries = ["India","USA","Germany","China", "France","Japan", "Australia", "Greece"] override func viewDidLoad() { super.viewDidLoad() topPickerView.delegate = self topPickerView.delegate?.pickerView?(topPickerView, didSelectRow: 0, inComponent: 0) topPickerView.delegate?.pickerView?(topPickerView, didSelectRow: 0, inComponent: 1) createAnotherPicker() } func createAnotherPicker() { anotherPicker.delegate = self anotherPicker.delegate?.pickerView?(anotherPicker, didSelectRow: 0, inComponent: 0) myTextField.inputView = anotherPicker } func numberOfComponents(in pickerView: UIPickerView) -> Int { if pickerView == topPickerView{ return 2 } else{ return 1 } } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if pickerView == topPickerView{ if component == 0{ return arrayOf2.count } else{ return arrayOf100.count } } else{ return arrayOfCountries.count } } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { if pickerView == topPickerView{ if component == 0 { return String(arrayOf2[row]) } else{ return String(arrayOf100[row]) } } else{ return arrayOfCountries[row] } } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { if pickerView == topPickerView{ let digitsValue = arrayOf2[topPickerView.selectedRow(inComponent: 0)] let decimalValue = arrayOf100[topPickerView.selectedRow(inComponent: 1)] myLabel.text = "Value is (digitsValue).(decimalValue)" if component == 0 { print(String(arrayOf2[row])) } else{ print(String(arrayOf100[row])) } } else{ myTextField.text = arrayOfCountries[row] } } } |
The output of the above-updated application in action is :
In order to dismiss the UIPickerView, we can set the touchesBegan
method with view.endEditing(true)
.
An even better option is to add a UIToolbar with a dismiss button on the UIPickerView.
UIPickerView with UIToolbar
Add the following function in your ViewController.swift file
1 2 3 4 5 6 7 8 9 10 11 |
func createToolbar() { let toolbar = UIToolbar() toolbar.sizeToFit() let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ViewController.closePickerView)) toolbar.setItems([doneButton], animated: false) toolbar.isUserInteractionEnabled = true myTextField.inputAccessoryView = toolbar } |
We’ve added a Button in the UIToolBar and set the Toolbar as the inputAccessoryView. That means it would be shown above the UIPickerView when the UITextField is clicked.
When the Done button is clicked, the following method would get executed:
1 2 3 4 5 6 |
@objc func closePickerView() { view.endEditing(true) } |
This will close the input view.
Don’t forget to add the method createToolbar() in your viewDidLoad method.
The output of the application in action is:
This brings an end to this tutorial. You can download the project from the link below: