I need to implement UIPickerView like this:
But default implementation gives this:
I used this UIPickerDatasourse method:
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
var pickerLabel = view as? UILabel;
if (pickerLabel == nil)
{
pickerLabel = UILabel()
pickerLabel?.textAlignment = NSTextAlignment.Center
}
pickerLabel?.attributedText = help_getAttributedStringForWalletByAmount(ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts[row].balance, currency: EnumCurrency(rawValue: ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts[row].currency))
pickerLabel?.sizeToFit()
return pickerLabel!;
}
Is it possible to make bigger scaling? Or may be is there any other workaround ?
You can try like,
func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
let color = (row == pickerView.selectedRowInComponent(component)) ? UIColor.orangeColor() : UIColor.blackColor()
return NSAttributedString(string: colors[row], attributes: [NSForegroundColorAttributeName: color])
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadAllComponents()
}
It is changing color, you try fontsize in attributed string.
Update:
refer this answer as mentioned in it don't implement titleFoRrow at all only implement viewForRow. and setup label with desired font size.
Hope this will help :)
Lion's answer actually works, but it's not smooth, so when you select another row, it's not user friendly (I think it works with colours, but for different fonts it's not the best solution). So I decided to affine transforms. Here is the code:
// MARK: - Picker View Help
func pickerViewHelp_afterRowWasSelected(row: Int) {
let accountSelected = ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts[row]
// save ID of this currency account in NSDefaults
DefaultsManager.sharedInstance.getDefaultsForSharingBetweenExtensions().setValue(accountSelected.id, forKey: kNSDefaults_mainCurrencyAccountID)
DefaultsManager.sharedInstance.getDefaultsForSharingBetweenExtensions().synchronize()
// reload scales
delay(0) { [weak self] in
self?.pickerViewHelp_updateFontsForAllRows(self!.pickerViewAccounts, selectedIndex: row)
}
}
func pickerViewHelp_updateFontsForAllRows(pickerView: UIPickerView, selectedIndex: Int) {
if pickerViewHelp_rowWasChangedBeforeReloadingPicker { // we changed the row
// remove prev animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
let pickerLabel = pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
pickerLabel?.layer.removeAllAnimations()
}
// start new animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
UIView.animateWithDuration(0.3) { [weak self] in
let scale: CGFloat = (i == selectedIndex) ? 1 : 0.5
// let pickerLabel = pickerView.viewForRow(i, forComponent: 0) as? UILabel
let pickerLabel = self?.pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
var transform = CATransform3DIdentity
transform = CATransform3DScale(transform, scale, scale, 1.01)
pickerLabel?.layer.transform = transform
}
}
}
else if pickerViewHelp_previouslySelectedRow == -1 { // first setup of the picker or we selected the same row
// remove prev animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
let pickerLabel = pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
pickerLabel?.layer.removeAllAnimations()
}
// without animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
let scale: CGFloat = (i == selectedIndex) ? 1 : 0.5
let pickerLabel = pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
var transform = CATransform3DIdentity
transform = CATransform3DScale(transform, scale, scale, 1.01)
pickerLabel?.layer.transform = transform
}
}
else { // repeat 1 if (for now I want leave in like this, because if smth is wrong, I will need to change it separately
// remove prev animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
let pickerLabel = pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
pickerLabel?.layer.removeAllAnimations()
}
// start new animation
for i in 0..<pickerView.numberOfRowsInComponent(0) {
UIView.animateWithDuration(0.3) { [weak self] in
let scale: CGFloat = (i == selectedIndex) ? 1 : 0.5
// let pickerLabel = pickerView.viewForRow(i, forComponent: 0) as? UILabel
let pickerLabel = self?.pickerViewHelp_dictOfViewsInPicker[i] as? UILabel
var transform = CATransform3DIdentity
transform = CATransform3DScale(transform, scale, scale, 1.01)
pickerLabel?.layer.transform = transform
}
}
}
}
// MARK: - Picker view
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if ApiManager.sharedInstance.userService_currentUser?.arrayCurrencyAccounts == nil { // no account
return 0
}
else {
let count = ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts.count
return count
}
}
var pickerViewHelp_rowWasChangedBeforeReloadingPicker = false
var pickerViewHelp_dictOfViewsInPicker = [Int: UIView]()
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
var pickerLabel = view as? UILabel;
if (pickerLabel == nil)
{
pickerLabel = UILabel()
pickerLabel?.textAlignment = NSTextAlignment.Center
}
pickerLabel?.attributedText = help_getAttributedStringForWalletByAmount(ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts[row].balance, currency: EnumCurrency(rawValue: ApiManager.sharedInstance.userService_currentUser!.arrayCurrencyAccounts[row].currency), scaleOfText: 1)
pickerViewHelp_dictOfViewsInPicker[row] = pickerLabel
return pickerLabel!;
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 60
}
var pickerViewHelp_previouslySelectedRow = -1
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerViewHelp_previouslySelectedRow != row {
pickerViewHelp_rowWasChangedBeforeReloadingPicker = true
}
else {
pickerViewHelp_rowWasChangedBeforeReloadingPicker = false
}
pickerViewHelp_previouslySelectedRow = row
pickerView.selectRow(row, inComponent: 0, animated: false) // because otherwise sometimes it stops between cells in the picker
if pickerViewHelp_rowWasChangedBeforeReloadingPicker {
// print("reload all components")
pickerView.reloadAllComponents()
}
pickerViewHelp_afterRowWasSelected(row)
}
It's not ideal either, but our designer liked it so we decided to use this way
Related
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"
}
}
}
...
I've meticulously searched through multiple pages and posts but couldn't quite get exactly what I need. I am currently working on a project and one of the controllers has several text fields with outputs using a single UIPickerView, and sometimes the labels need to change depending on the user's selection.
How would I change a label according to a UIPickerView's selected row, especially in an if statement?
I made a simple test code and example to demonstrate.
Code
class TestViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var categoryOutput: UITextField!
#IBOutlet weak var shapeOutput: UITextField!
#IBOutlet weak var lengthDiaOutput: UITextField!
#IBOutlet weak var heightOutput: UITextField!
#IBOutlet weak var dimensionLabel: UILabel!
let category = ["Perimeter", "Area"]
let shape = ["Rectangle", "Circle", "Triangle"]
// MARK: - viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
createCategoryPicker()
createShapePicker()
}
// MARK: - UIPickerViews
// Create a UIPickerView as an input text field for 'Category'.
func createCategoryPicker() {
let categoryPicker = UIPickerView()
categoryPicker.delegate = self
categoryPicker.tag = 1
categoryOutput.inputView = categoryPicker
categoryPicker.backgroundColor = UIColor(red: 238/255.0, green: 238/255.0, blue: 238/255.0, alpha: 1.0)
}
// Create a UIPickerView as an input text field for 'Shape'.
func createShapePicker() {
let shapePicker = UIPickerView()
shapePicker.delegate = self
shapePicker.tag = 2
shapeOutput.inputView = shapePicker
shapePicker.backgroundColor = UIColor(red: 238/255.0, green: 238/255.0, blue: 238/255.0, alpha: 1.0)
}
}
// MARK: - Extensions
// Create a UIPickerView.
extension TestViewController: UIPickerViewDelegate, UIPickerViewDataSource {
// Set number of lists.
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// Set number of rows in list.
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView.tag == 1 {
return category.count }
if pickerView.tag == 2 {
return shape.count }
return 0
}
// Set content of list.
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView.tag == 1 {
return category[row] }
if pickerView.tag == 2 {
return shape[row] }
return nil
}
// Grab selection and change label.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 1 {
categoryOutput.text = category[row] }
if pickerView.tag == 2 {
shapeOutput.text = shape[row]
if component == 1 {
dimensionLabel.text = "Diameter" }
else {
dimensionLabel.text = "Length" }
}
}
// Set appearance of contents.
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var label: UILabel
if let view = view as? UILabel {
label = view }
else { label = UILabel() }
if pickerView.tag == 1 {
label.text = category[row] }
if pickerView.tag == 2 {
label.text = shape[row] }
label.font = UIFont(name: "Avenir", size: 17)
label.textColor = .black
label.textAlignment = .center
return label
}
}
This is the section that needs focusing.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 1 {
categoryOutput.text = category[row] }
if pickerView.tag == 2 {
shapeOutput.text = shape[row]
if component == 1 {
dimensionLabel.text = "Diameter" }
else {
dimensionLabel.text = "Length" }
}
}
Example
The text label, Dimension, will not change to Diameter when Circle is selected.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 1 {
categoryOutput.text = category[row] }
if pickerView.tag == 2 {
shapeOutput.text = shape[row]
if row == 1 //Circle{
dimensionLabel.text = "Diameter" }
else {
dimensionLabel.text = "Length" }
}
}
Both of your picker views only have 1 component which is component 0.
"Circle" is in the 2nd row (row 1), so your if statement needs to check for row == 1, not component == 1.
I have to change the color of the selected row in a UIPickerView.
I did managed to change the color, i know that the question already have several replies, anyway those do not satisfy me: with those implementation, the animation of the pickerview is glitchy and i don't like it.
This is the code of the current solution
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var label: UILabel
if view == nil {
label = UILabel()
} else if view is UILabel {
label = view as! UILabel
} else {
label = UILabel()
}
let title: NSAttributedString
if self.model?.selectedValue == row {
title = UIPickerView.attributedString(with: .selectedRow, text: "\(model?.years[row] ?? 0)")
} else {
title = UIPickerView.attributedString(with: .unselectedRow, text: "\(model?.years[row] ?? 0)")
}
label.attributedText = title
return label
}
And when the user scrolls, I reload the components.
But as you can see in the images below, when a user scroll, the green field moves and there is a fraction of seconds in which the green label is below the selector indicator and the selected row is black.
What I'd like to have is that everything inside the selector indicator is green while what outside keeps the default shades of grey.
How can I implement this?
You should use attributedTitleForRow for this instead, no need to create your own label with an NSAttributedString. In your didSelectRow your reload all your components to be able to reset all colors and set the new selected one to green.
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
let color = (row == pickerView.selectedRow(inComponent: component)) ? UIColor.green : UIColor.black
return NSAttributedString(string: self.model[row], attributes: [NSForegroundColorAttributeName: color])
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadAllComponents()
}
You can simply use this code
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let label = view as? UILabel ?? UILabel()
if pickerView.selectedRow(inComponent: component) == row {
label.backgroundColor = UIColor.green
label.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
label.layer.cornerRadius = 18
label.layer.masksToBounds = true
label.textColor = .white
label.text = String(numbers[row])
label.textAlignment = .center
}else {
label.layer.cornerRadius = 25
label.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
label.layer.cornerRadius = 18
label.layer.masksToBounds = true
label.textColor = .white
label.text = String(numbers[row])
label.textAlignment = .center
}
return label
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadAllComponents()
}
Better effects with performance a little bad.
extension ViewController: UIPickerViewDelegate{
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let info = BeatScalar.generalRates[row]
let general = GeneralRateItem(info.cn, info.ita, info.val)
// gray every row
general.unselected()
decorateView(pickerView, row: row)
return general
}
// Here is the logic
func decorateView(_ picker: UIPickerView, row: Int){
var frame = picker.frame
frame.origin.y = frame.origin.y + frame.size.height * 0.42
frame.size.height = frame.size.height * 0.16
let mini = max(row-1, 0)
// 19 is total number
let maxi = min(18, row+1)
for i in mini...maxi{
if i != row, let item = picker.view(forRow: i, forComponent: 0) as? GeneralRateItem{
let f = item.convert(item.frame, to: picker)
if frame.intersects(f) == false{
// highlight the center row
item.selected()
}
}
}
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 44
}
}
extension ViewController: UIPickerViewDataSource{
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { // 19 is total number
return 19
}
}
I see many solutions out there for the UIPickerView font size, but it seems they are all based on text based arrays and / or require a UIViewController.
I am using an Int Array within a UITableViewCell and cannot seem to find something that will work with what I am trying to accomplish.
Here is the code:
import UIKit
class AirTemperatureTableViewCell: UITableViewCell, UIPickerViewDelegate, UIPickerViewDataSource
{
let numberOfComponents: Int = 2
let temperatureComponentRows: Int = 501
let temperatureSymbolComponentRows: Int = 2
let Fahrenheit: String = "F"
let Celsius: String = "C"
let minDegrees = -250
let maxDegrees = 250
private var degrees: Array<Int> = [Int]()
var temperature: Int = 30 // our default temperature
var temperatureType: String = "C" // our default type is Celsius
#IBOutlet var airTemperaturePicker: UIPickerView!
override func awakeFromNib()
{
super.awakeFromNib()
for i in self.minDegrees ..< self.maxDegrees+1
{
self.degrees.append(i)
}
self.airTemperaturePicker.selectRow(280, inComponent: 0, animated: true)
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{
return self.numberOfComponents
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
if component == 0
{
return self.temperatureComponentRows
}
else
{
return self.temperatureSymbolComponentRows
}
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
//
// If we are component 0, the degrees, return the value for the given row.
//
if component == 0
{
return String(self.degrees[row])
}
else
{
if row == 0
{
return self.Celsius
}
else
{
return self.Fahrenheit
}
}
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
}
}
any help would be appreciated.
You can use a UILabel with the viewForRow method of the UIPickerViewDataSource. You can then configure it with all the regular label options incl. setting font size, color, etc.:
// goes in lieu of titleForRow if customization is desired
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
let pickerLabel = UILabel()
if component == 0 {
pickerLabel.textColor = .darkGrayColor()
pickerLabel.textAlignment = .Center
pickerLabel.text = String(self.degrees[row])
pickerLabel.font = UIFont(name:"Helvetica", size: 28)
} else {
pickerLabel.textColor = .redColor()
pickerLabel.textAlignment = .Center
pickerLabel.font = UIFont(name:"Helvetica", size: 28)
if row == 0 {
pickerLabel.text = self.Celsius
} else {
pickerLabel.text = self.Fahrenheit
}
}
return pickerLabel
}
You should use the UIPickerViewDelegate function viewForRow inside your UITableViewCell subclass like so:
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
let view = UIView(frame: picker.frame)
let label = UILabel(frame: picker.frame)
label.textAlignment = .Center
label.text = String(degrees[row])
label.font = UIFont(name: "Arial", size: 15)
label.adjustsFontSizeToFitWidth = true
view.addSubview(label)
return view
}
picker is an #IBOutlet for your UIPickerView in your UITableView subclass set using either the prototype cell or external nib and control-drag. Also, make sure to set the picker's delegate and dataSource properties inside awakeFromNib.
override func awakeFromNib() {
super.awakeFromNib()
picker.dataSource = self
picker.delegate = self
//Your Code Below
}
This should make a cell width pickerView with a UILabel of your font choice.
I have UIPickerView to display names using names Array
The first element of the array is default value "Select Name"
I want to display selected value in Gary color and rest of names in blue color
this func used to prevent selecting the default value:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row == 0 {
pickerView.selectRow(row+1, inComponent: component, animated: true)
selectedName = names[row+1]
} else {
selectedName = names[row]
}
}
and this func to change color
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
let pickerLabel = UILabel()
pickerLabel.textColor = (row == pickerView.selectedRowInComponent(component)) ? UIColor.grayColor() : UIColor.blueColor()
pickerLabel.text = names[row].name
pickerLabel.textAlignment = NSTextAlignment.Center
return pickerLabel
}
The problem is when I select the first value of the picker (not the default value), the color remains blue. All other items are working correctly (their color change to gray when I select them)
Use the PickerView reloadComponentMethod
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row == 0 {
pickerView.selectRow(row+1, inComponent: component, animated: true)
pickerView.reloadComponent(component)
selectedName = names[row+1]
}
else {
selectedName = names[row]
}
}
selectRow only spins the wheel to the new row. Calling reloadComponent refreshes the datasource to get new views
I do this just before returning the value on pickerView viewForRow or pickerView attributedTitleForRow:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
pickerView.reloadAllComponents() // hack to refresh all values while scrolling
})
It's hacky but it works good enough for me. I hope it helps :)
var calendarContents : [[String]] = []
let dates = ["1","2","3","4","5","6"]
let months = ["JAN", "FEB", "MAR"]
let year = ["2015", "2016","2017"]
override func viewDidLoad() {
super.viewDidLoad()
calendarContents = [dates,months,year]
// Do any additional setup after loading the view.
}
func numberOfComponents(in pickerView: UIPickerView) -> Int{
return calendarContents.count
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
return calendarContents[component].count
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
if pickerView.selectedRow(inComponent: component) == row {
pickerLabel.attributedText = NSAttributedString(string: calendarContents[component][row], attributes: [NSFontAttributeName:UIFont(name: "AvenirNext-Bold", size: 26.0)!, NSForegroundColorAttributeName: UIColor.yellow])
} else {
pickerLabel.attributedText = NSAttributedString(string: calendarContents[component][row], attributes: [NSFontAttributeName:UIFont(name: "Avenir Next", size: 22.0)!, NSForegroundColorAttributeName: UIColor.white])
}
pickerLabel.textAlignment = .center
return pickerLabel
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadAllComponents()
}