I am attempting to write an iPhone application that makes unusual use of the UIPicker. Specifically, I am attempting to load a limited number of items into the picker an then, when the user presses a button, have the picker spin and land on a random selection... An example of what I am trying to achieve can be seen in the latest offering from Urban Spoon in the Apt Store...
Does any one have an idea on the best way to accomplish the spinning effect?
Well, I had a couple of ideas, but haven't tried any of them. One idea was to have additional dummy rows in the table - I was thinking of repeating the values for a while. The other thought was to subclass UIPickerView and tweak the animation settings. The latter is cleaner, I suspect the former is a lot easier...
I would like to know this as well, as I have a business requirement for this same type of thing. Especially like how UrbanSpoon even blurs the entries upon spinning.
And Jeff, the book you did with Dave was one of the best programming books I have ever read and is the only reason I understand iPhone development as well as I do today.
Thanks - I appreciate you saying that about the book.
As for spinning a picker, I haven't actually tried to do what they did in Urban Spoon - our book example just spins once, but my guess is that their picker datasource "lies" about the number of rows, saying there are more than there really are, so let's say there are 10 rows, the data source might say there are 100 rows in the component (actual count multiplied by 10 - just picking a multiplier out of the air), then when the component asks for a row, it just calculates the requested row number modulus the actual row count to determine the row to feed, so in our case, when it asks for row 31, 31%10 = 1, so it feeds row 1. That way, you would have the illusion of many rows, but it's really just the same rows over and over again.
As for the "blur" effect, I'm guessing that the data source is not supplying strings, it's suppling views, and I'm guessing it's creating an imageview based on the text that would be there and supplies that when it's spinning. That's just a guess, though, I don't know for sure, and I haven't tried it myself.
So check this out, I looked at the UrbanSppon app a little more in detail, and the first two components seemingly have an infinite amount of data. If you scroll up to the A's, you will see that there is no white space above it and it immediately shows the end of the alphabet again.
I tried to keep going for a while to see if maybe they just had a massive amount of data but to no avail. It just seemed to loop over and over again. Pretty clever this little app is.
They probably set the row at the count of objects + 1, and when the picker gets set to a number below count, they probably switch it to a higher number and don't animate the change, same thing if they go above the highest number..
hey jeff....im having a little trouble with this still. First of all, your book is excellent, beats the books from CS classes in college. However, my app closes when i press my button that spins my UIPicker. Below is my spin method. any ideas as to why its not spinning, and just closing out in the iphone simulator?
int numInRow = 1;
int lastVal = -1;
for (int i = 0; i < 5; i++) {
int newValue = random() % [self.names count];
I'm working on a similar app at the moment that uses 3 picker wheels to play three sounds. It can be spun manually and works fine, but I'm trying to get it working with a random button.
I'm using arc4random() to spin the wheels to random, and I've got it to display an alert message with the random selection (by adding a 0.2 delay time), but the problem is that I can't get it to play any sounds from random.
If I have manually selected rows before hitting the random button then it will play the last manually selected sounds, but never the randomly selected sounds.
Code:
- (void)firstColumn {
switch (whatSound) {
case 0: // do nothing
break;
case 1: // do nothing [select]
break;
case 2: AudioServicesPlaySystemSound(bestSoundID);
break;
case 3: AudioServicesPlaySystemSound(bigMoustacheSoundID);
///////more in here/////
default: // do nothing
break;
}
}
- (void)secondColumn {
switch (secondSound) {
case 0: // do nothing
break;
case 1: // do nothing [select]
break;
case 2: AudioServicesPlaySystemSound(bestSoundID);
break;
case 3: AudioServicesPlaySystemSound(bigMoustacheSoundID);
break;
///////more in here////////
default: // do nothing
break; }
}
- (void)thirdColumn {
switch (thirdSound) {
case 0: // do nothing
break;
case 1: // do nothing [select]
break;
case 2: AudioServicesPlaySystemSound(bestSoundID);
break;
case 3: AudioServicesPlaySystemSound(bigMoustacheSoundID);
break;
/////////more in here//////////
default: // do nothing
break; }
}
/////normal play action in here//////
- (IBAction)randomAction
{
{
[triplePicker selectRow:arc4random() % [firstHalf count] inComponent:kFirstComponent animated:YES];
[triplePicker selectRow:arc4random() % [secondHalf count] inComponent:kSecondComponent animated:YES];
[triplePicker selectRow:arc4random() % [thirdHalf count] inComponent:kThirdComponent animated:YES];
}
{
[self performSelector:@selector(messageMe) withObject:nil afterDelay:(0.2)];
}
{
[self performSelector:@selector(randomPlay) withObject:nil afterDelay:(1)];
}
}
- (void)pickerView:(UIPickerView *)triplePicker didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (component==kFirstComponent) {
whatSound = row +1;
} else {
if (component==kSecondComponent) {
secondSound = row +1;
} else {
if (component==kThirdComponent) {
thirdSound = row +1;
}
}
}
}
- (void)messageMe {
NSInteger firstRow = [triplePicker selectedRowInComponent:kFirstComponent];
NSInteger secondRow = [triplePicker selectedRowInComponent:kSecondComponent];
NSInteger thirdRow = [triplePicker selectedRowInComponent:kThirdComponent];
NSString *first = [firstHalf objectAtIndex:firstRow];
NSString *second = [secondHalf objectAtIndex:secondRow];
NSString *third = [thirdHalf objectAtIndex:thirdRow];
NSString *message = [[NSString alloc] initWithFormat:
@"%@ %@ %@.", first, second, third];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:
@"Dr Belond Says:"
message:message
delegate:nil
cancelButtonTitle:@"I Love You!!"
otherButtonTitles:nil];
[alert show];
[alert release];
[message release];
}
- (void)playMe {
[self firstColumn];
[self performSelector:@selector(secondColumn) withObject:nil afterDelay:(1)];
[self performSelector:@selector(thirdColumn) withObject:nil afterDelay:(2)];
}
Has anyone come across a problem like this? It seems like it doesn't acknowledge the selected row to play the sound unless it's manually selected, but still acknowledges it to display the correct alert.