Horizontally shifted hidden rows in UIPickerView with 2 components - ios

I have a UIPickerView with 2 components:
The hidden rows however are shifted towards the center. I think it has to do with the space that UIPickerView places between the 'wheels'.
I don't see anything in iOS' rather brief documentation discussing how to prevent this.
Here's my code:
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat
{
return self.currenciesPicker.width / 2
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat
{
return 50.0
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
{
var cell: CurrencyPickerCell
if view == nil
{
let width = self.pickerView(pickerView, widthForComponent: component)
let height = self.pickerView(pickerView, rowHeightForComponent: component)
cell = CurrencyPickerCell(frame: CGRect(x: 0.0, y: 0.0, width: width, height: height))
}
else
{
cell = view as! CurrencyPickerCell
}
let code = self.codes[row]
cell.nameLabel.text = Currency.names[code]
cell.symbolLabel.text = Currency.symbols[code]
return cell
}
When I let widthForComponent return half the picker's size minus 20, the cells just show up 20 point smaller. This creates empty borders on the left and right ends of the picker view. It does not change this weird 'parallax'.
Does anyone have an idea what's causing this and how to prevent it?
How should I calculate widthForComponent (is half the width of the picker correct)?

Unfortunately this is how the UIPickerView control is designed. It's supposed to look like a couple of wheels sitting side by side that you are looking at from directly above. It's a bit of a strange one considering all the push towards a flat design style Apple has made but there is no way to change it.
The only real options are to do it yourself, either completely manually or possibly subclassing UIPickerView and handling the drawing yourself, or to use a 3rd party control.

Related

How to update a UIPickerview after changing it's data source contents

I have 2 UIPickerViews in an ios program which I am running on an iPad simulator.
They have one component in each.
I find the relevant picker view by using a switch on the tag. The two single component views need to be changed by adding or deleting components.
This is easy enough in the data source with
pickerData.append(textInput)
pickerData.sort()
pickerData.reloadAllComponents
and
pickerData.remove(at: lastDataSelected)
picker.reloadAllComponents()
where lastDataSelected is the row integer.
This works to change the data source but not entirely when transferred to the UIPickerViews.
The UIPickerView display is not updated until I scroll the view. To be more precise, the item selected is correct but the text label is not updated. After scrolling the data labels are all showing correctly.
I have tried to programatically scroll from one end to the other but this does not help.
So how can I tell the program to update the view without the user scrolling it?
picker.reloadInputViews() does not help.
Apart from this the number of items (rows) isn't changed to reflect the changes in the picker data so the last item falls off the list when adding a new one.
So the second question is how to get the UIPickerView functions to update the number of rows?
I haven't been able to find any examples of dynamically updated picker views so hope someone can help or point me in the right direction.
The remaining code is fairly standard I believe but I'm obviously missing something in the update process.
override func viewDidLoad() {
super.viewDidLoad()
flvPicker = UIPickerView()
flvPicker.delegate = self
flvPicker.dataSource = self
flvPicker.tag = 0
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
switch pickerView.tag {
case 0:
return 1
case 1:
etc...
}
}
var numberOfRowsInComponent = 0
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch pickerView.tag {
case 0:
return flvPickerData.count
case 1:
etc...
}
}
func pickerView(_
pickerView: UIPickerView,
titleForRow row: Int, forComponent component: Int) -> String? {
switch pickerView.tag {
case 0:
return flvPickerData[row]
case 1:
etc...
}
}
func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch pickerView.tag {
case 0:
flavourSelected = flvPickerData[row]
lastFlavourSelected = row
case 1: etc...
}
}
I think the question is really how to get the UIPickerView to update correctly after making changes to it's data source and therefore row count.
You can use reloadComponent(_:) method from UIPickerView.
A little late to the party, but if you want to update a picker view, there's also the method selectRow. This also has the benefit of an animation property, so you can animate any updates.
Example:
for (index, day) in weeklyOptions[0].enumerated() {
if scheduledTime.contains(day) {
weeklyDatePicker.selectRow(index, inComponent: 0, animated: true)
}
}

How to create date scroller in ios

I am looking to create a date scroller in iOS. I am trying to reproduce the scroller found in the native calendar app in day view with the sun-sat days and the ability to scroll left and right to view other weeks.
What is the best way to go about achieving this?
I have tried a ContainerView with swipe gestures and then I thought I would replace the view in the container with a new one (copy of the same view but the previous/next weeks dates). However when adding a new view it takes over the whole view and not just the view container.
The design of the app is:
NavViewController -> ViewController -> Container ->
SwipeViewController
Inside the View Controller I have this in the swipe action method:
let viewController = self.storyboard!.instantiateViewController(withIdentifier: "swipeViewControllerStoryboard") as! SwipeViewController
self.swipeContainer.addSubview(viewController.view)
I am not sure I understand it very well but creating custom PickerView is more or less the same as creating any other component i.e tableViews. create an IBOutlet pickerView. Create class that inherits from UIPickerView and implement:
UIPickerViewDataSource
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1 //maybe more?
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return yourArray.count
}
UIPickerViewDelegate
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return (CGFloat)70
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let view = UIView(frame: CGRect(x: 0, y: 0, width: customWidth, height: 100)) //height CGFloat
//And create your labels here and add to view.addSubView(label)
//let label = UILabel(frame: CGRect(x: 0, y: 0, width: customWidth, height: 70))
//...
//..
//.
//use CGAffineTransform and rotate the picker to horizontal
view.transform = CGAffineTransform(rotationAngle: 90 * (.pi/180))
return view
}
Back to your ViewController instantiate the CustomPicker. Set the delegate and datasource of the pickerView to your CustomPicker instance.
I am sure there are many ways of doing this and it can be a hack. Maybe rather find a way to customise the UIDatePicker, but should you want to customise your pickerViews with any other data, I would go this route.

UIPickerView Image Quality Loss

I just set up a UIPickerView with different images in each row using
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let rowImg = UIImage(named: array[row] + ".png")
let rowView = UIView(frame: CGRect(x:0,y:0,width:60,height:60))
rowView.backgroundColor = UIColor(patternImage: rowImg!)
return rowView
}
I noticed that the image was softened more than I like and the color went from a sharp red to almost a soft red-orange. Anyway around this?

Weird graphical issue with UIPickerView

I tried to put a UIPickerView in a UIViewController and show a simple items in it with this code:
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 3
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 10
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
pickerLabel.textColor = UIColor.black
pickerLabel.text = "10"
pickerLabel.textAlignment = NSTextAlignment.center
pickerLabel.sizeToFit()
return pickerLabel
}
everything is fine but when I changed numberOfComponents to 2 picker view didn't show correct. Why this is happening?(Xcode 8 iOS 10)
There are two things to notice here:
You have used: pickerLabel.sizeToFit() which would size the label to its content.
Next is that if you comment pickerLabel.sizeToFit() and put a background color to your label. You'd get the following result
As you can see in here that PickerView has a curvature and a distance in between cells which is causing this issue. So solution is you can give a width to your label & no size to fit and apply a background while testing your result and come to the best possible combination.
For instance, check the iOS Native clock timer:
"They have tried playing around with width of label and index"
Please note:
The curvature is causing the width to decrease and label is center aligned so it is taking it along the path of decreasing width, if you get what i'm trying to say here.
This should explain it.
Cheers!

UIPickerView is Selecting the Wrong Row-Swift

So I have UIPickerView that isn't working the way I want it to. It works correctly about 3/4 of the time, but the other 1/4 it doesn't.
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return listsArray.count
}
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView
{
activeQuizPlace = row
var pickerLabel = UILabel()
pickerLabel.textColor = UIColor.whiteColor()
pickerLabel.text = listsArray[row]
pickerLabel.font = UIFont(name: "Georgia", size: 22)
pickerLabel.textAlignment = NSTextAlignment.Center
return pickerLabel
}
The listsArray contains 5 items(which are strings). Rows 0-2 work correctly 100% of the time. However when row 3 is selected it occasionally says that row 1 was, and when row 4 is selected it sometimes says that row 2 was. I think the problem has something to do with the last function I have that controls the UIPickerView. I just copied that code from this website as a way to change the color and font of the text. Before I was using this function I never had a problem with it, or at least never noticed one. Side note: I am using Xcode 6.3.2
I need a way for the picker view to work correctly, as well as to be able to change its font and color. I would love help with this I've been looking for answers online for 2 hours and can't figure out what I'm doing wrong, thanks in advance!
I think you need to remove the line activeQuizPlace = row from the code you have shown and then add this function below.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
activeQuizPlace = row
}
The function you were using is not called with the index that the user selects, it is called with the index that the system needs for drawing the views.
The suggested function should be the one you are after (hopefully).

Resources