UIPickerView accessiblityLabelForComponent not being called - ios

I am trying to set accessibility label for UIPickerView component, but the delegate method is never called. What's more, UIInspector shows the pickerView is not accessible, but it has the label actually set.
The dataSource/delegate methods are fired. Only the UIAccessibilityDelegate is not.
Tested on xcode 10.1 iOS 12.1 simulator
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UIPickerViewAccessibilityDelegate {
#IBOutlet weak var pickerView: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
pickerView.isAccessibilityElement = true
pickerView.accessibilityLabel = "TESTAccLabel"
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 5
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return "\(component) - \(row)"
}
func pickerView(_ pickerView: UIPickerView, accessibilityLabelForComponent component: Int) -> String? {
return "TODO:JS"
}
}

Related

How to display a PickerView row content into a label

I'm new in Swift! and I'm learning from several sources.
I'm building a small app with only 2 elements ( PickerView and label )
I want to know how to let the PickerView row contents to be displayed into a label?
also is there a way to show more information for the row content?
import UIKit
class ViewController: UIViewController {
#IBOutlet var picker: UIPickerView!
let names = ["Sara", "Ali", "Joy"]
override func viewDidLoad() {
super.viewDidLoad()
picker.dataSource = self
picker.delegate = self
}
}
extension ViewController : UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return names.count
}
}
extension ViewController : UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return names[row]
}
}
For example : when Ali is chosen, I want to display "He scores 90" in the label
but I don't want the "He scores 90" sentence to be shown next to Ali in PickerView itself
Thank you
Thank you El Tomato for your hint
it's one of the delegate methods - didSelectRow
and it worked great
import UIKit
class ViewController: UIViewController {
#IBOutlet var picker: UIPickerView!
#IBOutlet var label: UILabel!
let names = ["Sara", "Ali", "Joy"]
override func viewDidLoad() {
super.viewDidLoad()
picker.dataSource = self
picker.delegate = self
}
}
extension ViewController : UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return names.count
}
}
extension ViewController : UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return names[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
label.text = names[row]
}
}

Creating Second Delegate

I'm trying to create a second UIPickerView delegate so I can control them individually instead of using if blocks. Below is an example I put together, I'm unsure of how to connect the second UIPickerView outlet to the second UIPickerView delegate (assuming that is all I am missing).
import UIKit
protocol secondDelegate {
func secondPickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
func secondNumberOfComponents(in pickerView: UIPickerView) -> Int
}
protocol secondDelegateDataSource {
func secondPickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
}
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, secondDelegate, secondDelegateDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = self
p1.dataSource = self
p2.delegate = self
p2.dataSource = self
}
#IBOutlet weak var p1: UIPickerView!
#IBOutlet weak var p2: UIPickerView!
var delegate2: secondDelegate?
var dataSource2: secondDelegateDataSource?
let picker1 = ["1","3","5"]
let picker2 = ["2","4","6"]
// first picker
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return picker1.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return picker1[row]
}
// second picker
func secondNumberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func secondPickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return picker2.count
}
func secondPickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return picker2[row]
}
}
So here's the problem: you are saying the words "second delegate", but in fact you still have just one delegate — the view controller.
That's your mistake. Make your deeds match your words. Get all the delegate code out of the view controller. Instead, give your view controller two helper objects — the two picker delegates. Route the dataSource and delegate properties of the two pickers correctly, one to each delegate. Now the messages are coming and going to completely separate places, and you will not have any single bottleneck with if clauses everywhere as you do now.
Here's a simplified example where the two helpers are instance of one class — naturally, nothing requires that you do it that way:
class Helper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(data[row])
}
}
class ViewController: UIViewController {
#IBOutlet weak var p1: UIPickerView!
#IBOutlet weak var p2: UIPickerView!
let helper1 = Helper(data:["Manny", "Moe", "Jack"])
let helper2 = Helper(data:["Harpo", "Chico", "Groucho"])
override func viewDidLoad() {
super.viewDidLoad()
p1.delegate = helper1
p1.dataSource = helper1
p2.delegate = helper2
p2.dataSource = helper2
}
}
If the two picker views do very different kinds of thing, then you would want two separate Helper classes, each of which acts as a picker view delegate in its own way. Again, the goal here is to avoid having to examine the pickerView in the datasource and delegate methods and decide with an if clause what to do; each Helper type would do just one thing.

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) {
}
}

Print to the console what is currently selected with my uipickerview?

Here is the code that I have:
class WelcomeViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var locationPicker: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
locationPicker.delegate = self
locationPicker.dataSource = self
}
var locationData = ["San Fransisco", "New York", "London", "Paris", "Rio", "Bejing"]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return locationData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return locationData[row]
}
}
I would like to print to the console the location that is currently selected so each location can send the user to a different screen.
You need the didSelectRow method of UIPickerViewDelegate.
func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int)
{
let location = locationData[row]
print(location)
}

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.

Resources