Get selected value from picker view (picker wheel) - ios

I'm currently using XCode version 11.3.1 (11C505) and Swift 5 and I can't seem to find a good answer as to how to get the selected value from a picker wheel (view). Here's the relevant code from my ViewController.swift
class ViewController: UIViewController {
#IBOutlet weak var numberPicker: UIPickerView!
#IBOutlet weak var test: UILabel!
private let possibleNums: [Int] = Array(1...16) // Create an array of Ints from 1 to 16
override func viewDidLoad() {
super.viewDidLoad()
numberPicker.dataSource = self
numberPicker.delegate = self
}
}
extension ViewController: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return possibleNums.count
}
// Attempt at getting the selected value, didn't work
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int {
print(possibleNums[numberPicker.selectedRow(inComponent: 0)])
test.text = "\(possibleNums[numberPicker.selectedRow(inComponent: 0)])"
}
}
extension ViewController: UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return String(possibleNums[row])
}
}
Edit: Solution was also in comments so I figured I'd put it here in case anyone else finds this:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int should be func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int (missing _)
and test.text = "\(possibleNums[numberPicker.selectedRow(inComponent: 0)])" should just be test.text = "\test.text = "\(possibleNums[row])"

Change test.text = "\(possibleNums[numberPicker.selectedRow(inComponent: 0)])" to this: test.text = "\(possibleNums[row])"
You only have one component, so you don't need to check for it, just return the row number as the array's index.

The easiest way to do that is to change your didSelectRow function from
test.text = "\(possibleNums[numberPicker.selectedRow(inComponent: 0)])"
to
test.text = "\(possibleNums[rows])"

Related

Swift 4.2 - PickerView not showing Content

this code makes me really mad. I already read thousands of tutorials and stack overflow comments....
Please help me. The Picker just contains a blank grey screen.
Code here:
GenderPickerModel.swift
import UIKit
class GenderPickerModel: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let genderPickerData: [String] = ["male", "female"]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1;
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return genderPickerData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return genderPickerData[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
}
}
and used in a Controller:
#IBOutlet weak var gender: UITextField!
private var genderPickerView: UIPickerView?
override func viewDidLoad() {
super.viewDidLoad()
loadProfile()
prepareView()
}
func prepareView() {
genderPickerView = UIPickerView.init()
let gpModel = GenderPickerModel()
genderPickerView?.delegate = gpModel
genderPickerView?.dataSource = gpModel
gender.inputView = genderPickerView;
genderPickerView?.selectRow(0, inComponent: 0, animated: true)
genderPickerView?.reloadAllComponents()
}
First, you do not need to do the separate array of gender in pickerview class and you don't need to create the instance of pickerview.
From this, you can see your datasource in your custompickerview
/**
Controller code where you can create instantiate picker assign data
*/
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
let genderPickerData : [String] = ["male", "female"]
override func viewDidLoad() {
super.viewDidLoad()
prepareView()
}
func prepareView() {
genderPickerView = UIPickerView()
let gpModel = GenderPickerModel()
gpModel.data = genderPickerData
gpModel.dataSource = gpModel
gpModel.delegate = gpModel
textField.inputView = gpModel
}
}
/**
Custom pickerview class where you can handle data
*/
import UIKit
class GenderPickerModel: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate {
var data = [String]()
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
}
}

Invalid redeclaration of 'numberOfComponents(in:)' error

Here's my code. I would say the steps I have taken, but they just don't make sense and I'd get made fun of, I am very new to Swift and Xcode. But how do I declare a group of components? I thought I spaced them enough, I have honestly searched for guides, but no one really focuses on dropdowns and variables within the dropdowns.
import UIKit
class SecondViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var backBTN: UIButton!
#IBOutlet weak var label: UILabel!
#IBOutlet weak var labelTwo: UILabel!
#IBOutlet weak var pickerView: UIPickerView!
#IBOutlet weak var pickerviewTwo: UIPickerView!
var pickerData = ["X", "Y"]
var pickerdataTwo = ["R","D","C"]
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
pickerviewTwo.delegate = self
pickerviewTwo.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
label.text = pickerData[row]
}
func numberOfComponents(in pickerviewTwo: UIPickerView) -> Int {
return 1
}
func pickerviewTwo(_ pickerviewTwo: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerdataTwo.count
}
func pickerviewTwo(_ pickerviewTwo: UIPickerView, titleForRow row: Int, forComponent
component: Int) -> String? {
return pickerdataTwo[row]
}
func pickerviewTwo(_ pickerviewTwo: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
labelTwo.text = pickerdataTwo[row]
}
}
Your picker view code is wrong. First, I would recommend changing the names of them from pickerView and pickerViewTwo to something more descriptive.
The required functions for picker view can't be used multiple times, thus you are getting the error. The proper way to do it is:
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent
component: Int) -> String? {
//After renaming the first pickerView to topPickerView
if pickerView == topPickerView {
return pickerData[row]
}
else {
return pickerDataTwo[row]
}
}
There should be an if-else in each of the required functions, with the if statement saying that if pickerView == oneOfThePickerViewsName, with the if else statement. Whats happening is when the pickers are being set up, it checks which picker it is and uses the code for that.
Here is how the rest should be formatted:
//pickerView has been renamed to topPickerView
func numberOfComponents(in pickerView: UIPickerView) -> Int {
//You wouldn't need to do this here as its the same for both of them.
//
if pickerView == topPickerView
{
return 1
}
else
{
return 1
}
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == topPickerView
{
return pickerData.count
}
else
{
return pickerdataTwo.count
// should actually be formatted pickerDataTwo because of camelCase.
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent
component: Int) -> String? {
if pickerView == topPickerView
{
return pickerData[row]
}
else
{
return pickerdataTwo[row]
// should actually be formatted pickerDataTwo because of camelCase.
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent
component: Int) {
if pickerView == topPickerView
{
label.text = pickerData[row]
}
else
{
labelTwo.text = pickerdataTwo[row]
// should actually be formatted pickerDataTwo because of camelCase.
}
}

How to connect pickerviews and labels in iOS?

I have two pickerView and two Label on my ViewController.
The question is how I could connect labels to pickerView's data array (string type) and show in labels chosen pickerView cell?
#IBOutlet weak var valuetype1: UILabel!
var pickerData: [String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.picker1.delegate = self
self.picker1.dataSource = self
self.picker2.delegate = self
self.picker2.dataSource = self
pickerData = ["Годы", "Месяцы", "Недели", "Дни", "Часы", "Минуты"]
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
valuetype1.text = pickerData[row]
valuetype2.text = pickerData[row]
}
How could you see I connected labels (valuetype(1..2)) to pickerData but it always show in both labels one String. I need to show in first label String chosen in pickerView1 and another string in second label, chosen in pickerView2.
UIPickerViewDelegate has a method called pickerView(_:didSelectRow:inComponent:). Add this method to your VC class. This method gets called whenever the user selects a row.
Your implementation should look somewhat similar to this.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
valuetype1.text = pickerData[row]
}
For more information refer to the apple docs: https://developer.apple.com/documentation/uikit/uipickerviewdelegate/1614371-pickerview
EDIT:
When you are using the same controller as a delegate for multiple UIPickerViews, then you can check which picker view triggered the method call simply by comparing the pickerView argument on the pickerView(_:didSelectRow:inComponent:) method.
Try this:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == picker1 {
valuetype1.text = pickerData[row]
} else if pickerView == picker2 {
valuetype2.text = pickerData[row]
}
}

PickerView shows only '?'

This is my source code and what I have done is make picker view on storyBoard. Make IBOutlet in this controller by contorl+drag.
It can be compiled however, only '?' appears in the picker view.
Where is the problem?
import UIKit
class SelectViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate{
var songNames = ["test1","test2","test3"]
#IBOutlet weak var songPicker: UIPickerView!
override func viewDidLoad(){
songPicker.delegate = self
songPicker.dataSource = self
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return songNames.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int) -> String? {
return songNames[row]
}
}
You have missed the forComponent parameter from the dataSource method. Add it in your titleForRow function like this:
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return songNames[row]
}
This should fix the problem you are having.

UIPickerView best practice?

One short question: on a registration process I would like to ask the user to choose a value from a list of values.
Is it the right way to use a view Controller adding there all text fields and for the values a picker view? As the picker view needs so much space in between the text fields area I wonder what the best practice in this case would be?
this is my code so far:
class RegisterViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{
#IBOutlet weak var gradeTextField: UITextField!
#IBOutlet weak var gradePicker: UIPickerView!
let gradePickerValues = ["5. Klasse", "6. Klasse", "7. Klasse"]
func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int{
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
return gradePickerValues.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return gradePickerValues[row]
}
func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int){
gradeTextField.text = gradePickerValues[row]
self.view.endEditing(true)
}
override func viewDidLoad() {
super.viewDidLoad()
statusMessageLabel.hidden = true
gradePicker.dataSource = self
gradePicker.delegate = self
gradePicker.hidden = true
gradeTextField.inputView = UIPickerView()
gradeTextField.text = gradePickerValues[0]
}
The pickerview is hidden at the beginning and appears only when I select the text field, this is fine so far... But the the picker view is empty...
It depends on controller appearance. If there only one choose action per screen it will be better to put Table View on it and selected row will be current selection.
If screen has multiply fields, that user should act with, then, in my opinion, it's better to put label + button above it and when user press this button you just shows Picker View from screen bottom. When user select any row in Picker View you change label text, but don't hide picker itself, it should be done by pressing "Done" button you place above.
Hope this helps.
Update:
Your problem because you just forget to set dataSource property of UIPickerView
Just do: gradePicker.dataSource = self in viewDidLoad()
And don't forget to implements protocol here: class RegisterViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource
Update 2:
Finally made it. If you add UIPickerView in inputView of your textFiled, then It should NOT be in IB. So you could remove it from storyboard (or .xib, if you use it).
Then change code to be something like this:
class RegisterViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var gradeTextField: UITextField!
var gradePicker: UIPickerView!
let gradePickerValues = ["5. Klasse", "6. Klasse", "7. Klasse"]
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int{
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
return gradePickerValues.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return gradePickerValues[row]
}
func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int){
gradeTextField.text = gradePickerValues[row]
self.view.endEditing(true)
}
override func viewDidLoad() {
super.viewDidLoad()
gradePicker = UIPickerView()
gradePicker.dataSource = self
gradePicker.delegate = self
gradeTextField.inputView = gradePicker
gradeTextField.text = gradePickerValues[0]
}
}
First set delegate
UIPickerViewDataSource,UIPickerViewDelegate
set IBOutlet for UIPickerView
#IBOutlet weak var pickerView: UIPickerView!
Take an array for data
var arrayFruits = [String]()
Write this code on viewDidLoad()
arrayFruits = ["Apple","Banana","Orange","Grapes","Watermelon"]
self.pickerView.dataSource = self
self.pickerView.delegate = self
Write picker view delegate methods:
//MARK: - Pickerview method
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return arrayFruits.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return arrayFruits[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.labelFruit.text = arrayFruits[row]
}
100% working and tested

Resources