soleil
soleil

Reputation: 13085

UIPickerView - remove curvature and add text

I'm trying to create a UIPicker where I can select minutes and seconds. Here's the code:

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if(component == 0)
        return 24;

    return 60;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 30;
}

- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setAlignment:NSTextAlignmentCenter];
    [paragraphStyle setTailIndent:20];

    NSString *value = [NSString stringWithFormat:@"%d", row];

    return [[NSAttributedString alloc] initWithString:value
                                           attributes:@{NSParagraphStyleAttributeName:paragraphStyle}];
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
    return 160;
}

How can I get rid of the annoying curvature and just make vertical columns?

Also, how can I add "min" and "sec" to the selection row?

picker

Upvotes: 1

Views: 2739

Answers (3)

Jim
Jim

Reputation: 21

I have found that changing the width for the components has an effect on how much offset or curvature effect the UIPickerView applies to the selected row. In your delegate implement pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat and try returning values that are just large enough to show the information you want to display, say 40 or 60 for just two characters of text for a simple number. To change the spacing between columns/components you can add extra components that return 0 for number of rows, and use the width of these empty components to move around and adjust the placement of the components you're displaying data in.

Upvotes: 1

DBD
DBD

Reputation: 23233

As others have said, the existing API can't do it. If you want to do this, you'll have to write your own code to do it. I created a horizontal value picker in the past and it was annoying, but fairly straight forward. To do it I used a UILabel, an image and a UIScrollView.

First set up the UI

  1. Take the label and stick it in the scroll view. Populate the labels with the values you want.
  2. Set the scroll view height, width and position to show what you want the user to see. If you want the user to see the selected item and 3 on the top and 3 on the bottom then make it big enough to show 7 lines in the label.
  3. You image is the "selection indicator" you overlay this on top of the center item in the scroll view to show the user this is the selected item.
  4. If you want a pretty fade effect as your values go off the end you can create a white (or whatever background your app is) block which fades to transparent and overlay that over the top and bottom of the scroll view. This creates a fading number effect at the edges of the component.

Visually it show work... for the most part, but we need back end code to support it.

  1. Create a UIScrollViewDelegate and implement scrollViewDidScroll: which will tell you the content offset of your scroll view when the users changes it.
  2. Write a method that will convert the scroll view content offset to which "item" was selected. If you know how many lines are in the label (and you should) and you know how tall the label is (and you should) take the label height/lines to get how tall each "item" is. Then you take the content offset, divide by the item height, floor it and you know which line your are at... while remembering the content offset is from the TOP of your scroll view, so add in half the height. :)

So the basic functionality is done and it works, but it's not pretty.

The selected item didn't end centered in my selection image, which is just visually ugly. But you can fix it easily enough. You know the height of the items in the list and you know which item is selected, so programmatically scroll the wheel to have that item centered.

The other issue I had was momentum. Like a real wheel I wanted my picker to have momentum so if you gave it a hard flick it would go for a while, but if you gave it a gentle flick it would stop pretty fast. I had long list and if people were going from 7 to 70 I wanted them to be able to do it easily. If you are interested in in that, I can show you how I did it and post some code when I get back to the machine with my code on it.

Upvotes: 0

marko
marko

Reputation: 2084

Since you're making it into 24 mins and 60 secs, I'd fake it with 24h date picker. IMO

How can I get rid of the annoying curvature and just make vertical columns?

You don't. Else, implement your own using 2 table views or something.

Also, how can I add "min" and "sec" to the selection row?

NSString *value;

if(component == 0) value = [NSString stringWithFormat:@"%d min", row];
else  value = [NSString stringWithFormat:@"%d sec", row];

Upvotes: 0

Related Questions