In the clocks application, the timer screen shows a picker (probably a UIPicker
in UIDatePickerModeCountDownTimer
mode) with some text in the selection bar ("hours" and "mins" in this case).
(edit) Note that these labels are fixed: They don't move when the picker wheel is rolling.
Is there a way to show such fixed labels in the selection bar of a standard UIPickerView
component?
I did not find any API that would help with that. A suggestion was to add a UILabel
as a subview of the picker, but that didn't work.
Answer
I followed Ed Marty's advice (answer below), and it works! Not perfect but it should fool people. For reference, here's my implementation, feel free to make it better...
- (void)viewDidLoad {
// Add pickerView
self.pickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
[pickerView release];
CGSize pickerSize = [pickerView sizeThatFits:CGSizeZero];
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
#define toolbarHeight 40.0
CGFloat pickerTop = screenRect.size.height - toolbarHeight - pickerSize.height;
CGRect pickerRect = CGRectMake(0.0, pickerTop, pickerSize.width, pickerSize.height);
pickerView.frame = pickerRect;
// Add label on top of pickerView
CGFloat top = pickerTop + 2;
CGFloat height = pickerSize.height - 2;
[self addPickerLabel:@"x" rightX:123.0 top:top height:height];
[self addPickerLabel:@"y" rightX:183.0 top:top height:height];
//...
}
- (void)addPickerLabel:(NSString *)labelString rightX:(CGFloat)rightX top:(CGFloat)top height:(CGFloat)height {
#define PICKER_LABEL_FONT_SIZE 18
#define PICKER_LABEL_ALPHA 0.7
UIFont *font = [UIFont boldSystemFontOfSize:PICKER_LABEL_FONT_SIZE];
CGFloat x = rightX - [labelString sizeWithFont:font].width;
// White label 1 pixel below, to simulate embossing.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x, top + 1, rightX, height)];
label.text = labelString;
label.font = font;
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
label.alpha = PICKER_LABEL_ALPHA;
[self.view addSubview:label];
[label release];
// Actual label.
label = [[UILabel alloc] initWithFrame:CGRectMake(x, top, rightX, height)];
label.text = labelString;
label.font = font;
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
label.alpha = PICKER_LABEL_ALPHA;
[self.view addSubview:label];
[label release];
}
I received an answer that works well in iOS 7 to my question, which is a pretty cool trick.
The idea is to create multiple components, and for those label components, specify that it's a single row. For the embossed look that some people have, you can return NSAttributedStrings with the delegate method:
- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component
To re-create the embossed look for the labels...just create a image with the Text, so that you can easily apply a very similar effect to the text...and then use UIImageViews instead of Labels
Can you show where you define pickerTop and pickerSize?
That is what I have, but pickerTop seems to be wrong.
mike
Let's say we want to implement a picker view for selecting distance, there are 2 columns, one for distance, one for unit, which is km. Then we want the second column to be fixed. We can make it through some delegate methods.
Now we have this:
I guess this is the simplest way.
I also faced same problem. You can see working example in my custom made time picker published on GitHub:
https://github.com/kgadzinowski/iOSSecondsTimerPicker
It does exactly what you want.
There are 2 things you can do:
If each row and component in row is a simple text, than you can simply use the default UIPickerView implementation as is, and in your controller implement the following
UIPickerViewDelegate
methods :- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
to keep track of which row is selectedand return a different text for the selected row in your implementation of
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
If you need to have something other than text as the differentiator for the selected row, than you basically need to create your own
CustomPickerView
that derives from theUIPickerView
and thenFirst implement the
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated
and keep track of which row is selected.Then implement the
- (UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component
to generate a different view for the selected row.A sample for using the UIPickerView or implementing custom UIPickerView is available in the SDK, called UICatalog.