Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

theprizerevealed

macrumors regular
Original poster
Feb 26, 2016
183
12
Basically the uipickerview would play the role of display of output instead of its' normal role of input by selecting the data you want to proceed to use in some fashion.

So is this possible and where can I find the generic code to control the behavior of the uipickerview in terms controling the movement of the uipickerview without physical input by the user? thanks
 
Last edited:
First of all, I'd just like to point out that for technical issues like this, grammar and spelling are important to getting the best results.

Second, i can recommend the Stack Exchange Network.

Third, actually answering your question;

I'm not really sure you can get this behaviour from a PickerView. However, if it is possible, you would not control "movement" per se. You'd set up a Core Animation with a start and end position for the picker - That would typically be how UI movement is accomplished with UIKit.
 
Okay, well, I saw there was one grammar error. I just woke and I wrote hastily. I corrected that. As for the remainder, I use American spellings - not British.

I wasn't sure about whether the UIPickerVew could be used without physical input. I don't know much about Core Animation but I'll see what I can discover.
 
Okay, well, I saw there was one grammar error. I just woke and I wrote hastily. I corrected that. As for the remainder, I use American spellings - not British.

I wasn't sure about whether the UIPickerVew could be used without physical input. I don't know much about Core Animation but I'll see what I can discover.

Sorry if I seemed like a prick with respect to grammar. It wasn't to be a nazi. - I use text-to-speech since I have eyesight issues, and whilst I don't use it for code for obvious reasons, it makes text-chunks a lot faster for me to read. When I mention grammar, it's also things like capitalisation of UIPickerView, since it's a massive help for my text-to-speech, and your original post was slightly difficult to hear the meaning of although I got it, and have definitely read/heard worse. Of course my vision issue is my own, but making your text easy to read is appreciated by most tech communities regardless, so I still think my earlier post bears value.

Regarding your code issue, I still don't necessarily think you can use UIPickerView in that way, since it is definitely meant as an interactive element, but in general, if you want Views to move, the more or less 'official' approach is with CA.

If you only want it to be for a single selection (maybe multiple? I haven't actually tried this API) I did some quick research, and the View may have a pre-animated tool for exactly what you want.
Have a look at this documentation:
https://developer.apple.com/documentation/uikit/uipickerview/1614382-selectrow?language=objc

Important pointers for using CA.

CA is purely visual. You animate with key frames, meaning starting and ending positions (optionally middle positions as well) and the view will go through your key frames
This means however that the logic is not changed, so if you animate a CGRect to go off screen and onto screen with CA, it'll move from off-screen to onscreen, but if you don't also change its position property, it'll go right back after the animation completes.
 
Interesting concept. In general I hate pickers. They are very peculiar. Having said that, go for it and see how it looks.

The pickers have a set of apis that are pretty simple to display (and of course to choose) values. This is normally used to setup the initial or default value. It has animation built in I think so if you set a value it will spin to show that value. If you need to animate multiple values, one after another, you just need to have a delay between calls to set the picker's value.

The basic apis tell the picker how many rows and columns and the values or views for each row and column

You probably want to prevent the user from being able to change the picker's value while it's displaying itself. Not sure if there's an api for that but you can probably put a view in front of the picker that intercepts any touches.

Let us know how it goes.
 
Interesting concept. In general I hate pickers. They are very peculiar. Having said that, go for it and see how it looks.

What makes you say that?

You probably want to prevent the user from being able to change the picker's value while it's displaying itself. Not sure if there's an api for that but you can probably put a view in front of the picker that intercepts any touches.

In Storyboard you can disable interactivity, so there definitely is an API for that.
 
You can do what you want using a picker view but it's a bit awkward.
The picker view has a datasource so you need to update the data source, reload the view and then scroll to the selected index, probably 0 or last. You can do this animated or not. But this is all quite awkward.

A better approach is to use a UITableView. You still need to add your object to the datasource but then you can just insert a new tableview cell where you want it. UITableView is built for this kind of stuff and you will find it much easier to customise to look and behave the way you want it to.
 
I will investigate UITableView but I still wish to know the generic code that causes the UIPickerView to scroll without physical input.
 
If you look at the alarm clock app on iPad it uses a picker to set the alarm times. If you have two alarm times and the picker is showing and you move from one to the other the time animates to the new time.
 
If you look at the alarm clock app on iPad it uses a picker to set the alarm times. If you have two alarm times and the picker is showing and you move from one to the other the time animates to the new time.

I may be mistaken about what exactly you mean but that's not the behaviour I get. - For me, it closes the window with the picker and opens a new window with a new picker for the second alarm.
 
Hmmm. I'm sure I saw that behavior but now I can't reproduce it. Was writing from memory but not sure exactly what I did. Anyway, changing the picker's settings in code can make it animate the changes.
 
I'm experiencing some trouble writing the generic code for UIpickerview. How do I use the generic code found here:

https://developer.apple.com/documentation/uikit/uipickerview/1614382-selectrow?language=objc

I'm trying this:

Code:
func pickerView(_ pickerView: UIPickerView, selectRow row: lastrow, inComponent component: Int, animated: YES) -> String {}

How familiar are you with Swift? It looks like you're defining a new function that takes UI picker views and returns a string with no specific string specified for return. - Sometimes with UIKit you do define functions that the underlying framework then calls, but I would assume that this is a function that you call on the object instead of write for the object to call.
On your UIPicker use dot notation to call the function instead of defining a new one - In addition, where did -> String come from? Even if you were to define the function yourself, return type is specified as void in the docs.

But Xcode tells me that there are errors.

In future when you ask questions, specify the errors instead of just saying there are errors. We don't want to have to copy the code ourselves to get the compiler errors, and reading those can make debugging a whole lot faster, since we can reason about what the compiler tries to do and why it can't do it.
 
I'm trying this:

Code:
 func pickerView(_ pickerView: UIPickerView, selectRow row: lastrow, inComponent component: Int, animated: YES) -> String {}

But Xcode tells me that there are errors.

The method you show is not the same as the method in Apple's documentation. You use the selectRow:inComponent:animated method to select a row in a column in the picker. If animated is true then the picker will gradually select the row/column that you choose.

This is something like what you need:

Code:
picker.selectRow(row, inComponent: column, animated: true)
 
Wonderful! Thanks so much to both of you! I did a small test project and it works! The UIPickerView can act nicely as a display and creates a list in the UIPickerView. I can make it animate/rotate back to the most recent entry in the list in the UIPickerView automatically too, even after manually rotating the UIPickerView.

Hurrah!

Now to start coding the actual app....
 
There is a new problem that I need some suggestions about. Now I am trying to create a new UIPickerView with two components (two columns).

This differs from the other situation in the prior posts in this thread in that the left column/component is populated fully with a list beforehand; while the right column/component is meant to operate as in the manner described in the prior posts.

The issue is not with the population of the right column/component rather that it will not animate as described prior.

What happens is that the left column/component will animate as it should and roll through the list. However the right column, though it will populate with new entries in the list as it should do, will NOT animate/roll - rather it animates/rolls a single time for the first entry populated and then will NOT animate/roll any further. All new entries populating the list will appear below until no longer visible.

This is the code I'm using to try to use to animate both columns/components in the UIPickerView:

Code:
 picker.selectRow(row, inComponent: 0, animated: true)
            picker.selectRow(row, inComponent: 1, animated: true)

What could be the reason possibly for this behavior? Obviously something somewhere is coded wrongly but I don't know what.
 
You're starting the second animation before the first one is done. Often API's that start animations have a completion closure that's called when the animation is done. Apparently not in this case. You could put in a delay or put the first selectRow inside an animation block and the second one in the completion block. I would start trying with the delay. Try .2 seconds or longer delay.
 
You're starting the second animation before the first one is done. Often API's that start animations have a completion closure that's called when the animation is done. Apparently not in this case. You could put in a delay or put the first selectRow inside an animation block and the second one in the completion block. I would start trying with the delay. Try .2 seconds or longer delay.

Exactly my thought. This has screwed me over many, many times by now. Honestly, I wish animations would block the thread they're called from by default until they finish, and require the programmer manually start them off the main thread or something.
How do you create one of those animation blocks with a completion handler, for an animation that doesn't come with a built-in completion handler?
 
You surround the api call with an animation block. This is one way I've done this.

Code:
   UIView.animate(withDuration: 0.2, animations: {
     picker.selectRow(row, inComponent: 0, animated: true)
   }, completion: { finished in
     picker.selectRow(row, inComponent: 1, animated: true)  
   })
 
You surround the api call with an animation block. This is one way I've done this.

Code:
   UIView.animate(withDuration: 0.2, animations: {
     picker.selectRow(row, inComponent: 0, animated: true)
   }, completion: { finished in
     picker.selectRow(row, inComponent: 1, animated: true) 
   })


That's really damn great, and super useful to know! Thanks a damn lot. I'm not the OP but this is brillantly helpful to me too
 
well, I'm sorry to report that it doesn't work for me. :-(
I am wondering if maybe there is something coded wrongly in one of the UIPickerView functions?

I was using this video to help me to learn how to use multi-component UIPickerViews:


The same project is discussed in a webpage here:

https://www.iostutorialjunction.com...omponent-uipickerview-ios-swift-tutorial.html

if you look at his function here:

Code:
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return countriesArray[row]
}
return stateNumbersArray[row]
}

I tried it this way (with my own code) and I tried it with an else statement for the second return. Yet it still doesn't work. Should there be a second line of code related to component == 1 ? How would I write that? Everything that I tried then Xcode gave me errors.
 
Last edited:
I tried it this way (with my own code) and I tried it with an else statement for the second return. Yet it still doesn't work. Should there be a second line of code related to component == 1 ? How would I write that? Everything that I tried then Xcode gave me errors.


A return stops execution of the rest of the function. If the component value is 0, it'll return the names in the countries array to the UIPickerView for titles, and not execute anymore code. If the condition is not checked, it'll go to the next part and stop execution with the stateNumbers. If you only have two components, you don't technically need anymore. As it is here, it technically functions as an if-else. Though depending on how LLVM does its compiling, explicitly making it an else branch could perhaps speed up program execution, but that's irrelevant optimisation for now.

The code:
Code:
var x = 0
let y = 5
if (y==5) x+=2 else x+=3
will only execute x+=3 if the condition is not true. Whereas if written like your code snippe, it'd add 3 to x regardless of whether the if condition was met, and 2 was also added. But if the function returns inside the if statement, anything beyond that point is ignored anyway.

You say the animation block didn't work for you? How did it behave and can you share the animation block code snippet the way you've done it? Did you do it like in the example PhoneyDeveloper gave?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.