A UIPickerView with labels

I recently needed a picker view with labels (like the one in the timer tab in the Clock app) to select minutes and seconds for a time interval. So I made the following subclass of UIPickerView:

#import
/**
A picker view with labels under the selection indicator.
Similar to the one in the timer tab in the Clock app.
NB: has only been tested with less than four wheels.
*/@interfaceLabeledPickerView:UIPickerView{NSMutableDictionary*labels;}/** Adds the label for the given component. */-(void)addLabel:(NSString*)labeltextforComponent:(NSUInteger)component;@end

… and the implementation:

/*******************************************************************************
* Copyright (c) 2009 Kåre Morstøl (NotTooBad Software).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kåre Morstøl (NotTooBad Software) - initial API and implementation
*******************************************************************************/// http://stackoverflow.com/questions/367471/fixed-labels-in-the-selection-bar-of-a-uipickerview/616517#import "LabeledPickerView.h"
@implementationLabeledPickerView/** loading programmatically */-(id)initWithFrame:(CGRect)aRect{if(self=[superinitWithFrame:aRect]){labels=[[NSMutableDictionaryalloc]initWithCapacity:3];}returnself;}/** loading from nib */-(id)initWithCoder:(NSCoder*)coder{if(self=[superinitWithCoder:coder]){labels=[[NSMutableDictionaryalloc]initWithCapacity:3];}returnself;}-(void)dealloc{[labelsrelease];[superdealloc];}#pragma mark Labels
-(void)addLabel:(NSString*)labeltextforComponent:(NSUInteger)component{[labelssetObject:labeltextforKey:[NSNumbernumberWithInt:component]];}/**
Adds the labels to the view, below the selection indicator glass-thingy.
The labels are aligned to the right side of the wheel.
The delegate is responsible for providing enough width for both the value and the label.
*/-(void)didMoveToWindow{// exit if view is removed from the window or there are no labels.if(!self.window||[labelscount]==0)return;UIFont*labelfont=[UIFontboldSystemFontOfSize:20];// find the width of all the wheels combinedCGFloatwidthofwheels=0;for(inti=0;iwidthofwheels+=[selfrowSizeForComponent:i].width;}// find the left side of the first wheel.// seems like a misnomer, but that will soon be corrected.CGFloatrightsideofwheel=(self.frame.size.width-widthofwheels)/2;// cycle through all wheelsfor(intcomponent=0;component// find the right side of the wheelrightsideofwheel+=[selfrowSizeForComponent:component].width;// get the text for the label.// move on to the next if there is no label for this wheel.NSString*text=[labelsobjectForKey:[NSNumbernumberWithInt:component]];if(text){// set up the frame for the labelCGRectframe;frame.size=[textsizeWithFont:labelfont];// center it verticallyframe.origin.y=(self.frame.size.height/2)-(frame.size.height/2)-0.5;// align it to the right side of the wheel, with a margin.// use a smaller margin for the rightmost wheel.frame.origin.x=rightsideofwheel-frame.size.width-(component==self.numberOfComponents-1?5:7);// set up the labelUILabel*label=[[[UILabelalloc]initWithFrame:frame]autorelease];label.text=text;label.font=labelfont;label.backgroundColor=[UIColorclearColor];label.shadowColor=[UIColorwhiteColor];label.shadowOffset=CGSizeMake(0,1);/*
and now for the tricky bit: adding the label to the view.
kind of a hack to be honest, might stop working if Apple decides to
change the inner workings of the UIPickerView.
*/if(self.showsSelectionIndicator){// if this is the last wheel, add label as the third view from the topif(component==self.numberOfComponents-1)[selfinsertSubview:labelatIndex:[self.subviewscount]-3];// otherwise add label as the 5th, 10th, 15th etc view from the topelse[selfinsertSubview:labelaboveSubview:[self.subviewsobjectAtIndex:5*(component+1)]];}else// there is no selection indicator, so just add it to the top[selfaddSubview:label];}}}@end

A big thanks to dizy from stackoverflow.com for showing how to add the labels below the selection indicator.

If anyone knows of a better place to put the label-adding code than didMoveToWindow then please let me know. It seems out of place where it is now.