UIPicker sizing in landscape mode - iphone

I am trying to develop an app with a UIPicker in landscape mode, taking up (almost) the entire width of the screen (with 5 or 6 components). Can you please tell me how to set the size of UIPicker. Thank you very much for your help.

Actually, I resize my pickers for almost every app. I do not like that they take up the entire screen. Here is the method that I am using: (note that I am also rotating the picker to be horizontal)
in viewDidLoad .....
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
picker.delegate = self;
picker.dataSource = self;
picker.showsSelectionIndicator = NO;
//Resize the picker, rotate it so that it is horizontal and set its position
CGAffineTransform rotate = CGAffineTransformMakeRotation(-1.57);
rotate = CGAffineTransformScale(rotate, .46, 2.25);
CGAffineTransform t0 = CGAffineTransformMakeTranslation(3, 22.5);
picker.transform = CGAffineTransformConcat(rotate,t0);
[self.view addSubview:picker];
[picker release];
Then, I like to add a background image for my view that covers up the grey bars (which are now on the top and bottom) of the UIPicker:
//Create the overlay to superimpose ontop of the picker
//In this case, the image is the size of the screen with a transparent area the size of the //UIPickerView cut out in the middle
UIImageView *uiiv = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"problem_bg.png"]];
uiiv.userInteractionEnabled = NO;
uiiv.opaque = YES; //for performance
[self.view addSubview:uiiv];
[uiiv release];
UIPickerView delegate method:
-(UIView *) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)rowforComponent:(NSInteger)component reusingView:(UIView *)view
{
UIView *viewForRow = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 280)] autorelease];
UIImageView *img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myimage.png"]];
img.frame = CGRectMake(0, 0, 102,280);
img.opaque = YES;
[viewForRow addSubview:img];
[img release];
UILabel *label;
UIFont *font = [ UIFont fontWithName:#"Helvetica" size:20];
label = [[[UILabel alloc] initWithFrame:CGRectMake(10, 20, 270, 100)] autorelease];
label.text = #"I am a label";
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor blackColor];
label.font = font;
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
[viewForRow addSubview:label];
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57);
[viewForRow setTransform:rotate];
return viewForRow;
}
This gives a much smaller, horizontal picker with a nice look and feel. I hope this helps someone.

You can edit the size by opening the .xib file in TextEdit and changing the size of the UIPickerView.

You can't. UIPickerView's size is constant.
UPDATE: It turns out you can resize an UIPickerView. The trick is to place it inside another (smaller) UIView, and resize that view. I haven't tried this yet.
UPDATE 2: This method does not resize the UIPickerView, but rather crops it. It might or might not be what you're looking for, but AFAIK, there's no way to truly resize an UIPickerView, and this is as close as it gets. It doesn't look that bad.
UPDATE 3 (Long overdue): As of SDK 3.0, UIPickerView is completely resizeable using initWithFrame or setFrame.

I wrestled with the same issue of resizing the pickerview. After some research and headache here is something you can easily do:
Forget Interface builder! I think you can so much better UI without
the interface builder.
In your controllers overwrite the load view method.
-(void)loadView
{
//create your view
self.view = [[UIView alloc] initWithFrame:CGRectZero];
// create a default sized pickerView
pickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
pickerView.delegate = self;
pickerView.dataSource = self;
pickerView.showsSelectionIndicator = YES;
// Get its frame
CGRect pickerFrame = pickerView.frame;
// Set it to what ever you like, I use a default screen height times a shrink factor like 0.75 for 3/4 of its original size
pickerFrame.size.width = screenWidth*pickerShrinkFactor;
pickerFrame.size.height = pickerHeight*pickerShrinkFactor;
// You can also set the upper left corner of the picker
pickerFrame.origin.x = 0;
// Set the picker frame to new size and origin
pickerView.frame = pickerFrame;
// Add it to your view
[self.view addSubview:pickerView];
}
Good luck

I'm fairly certain that the UIPicker comes in one size, which you can't change. Would be interested to hear different.

The answer is in:
-(UIView *) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
Since with:
- (NSString*)pickerView:(UIPickerView*)pv titleForRow:(NSInteger)row forComponent:(NSInteger)component
Makes it work (that is: sideways with scaled label) of course

No problem (I just registered). By the way I just realized that when I posted my answer, that the method (UIView *) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent .... lost the space between row and forComponent. So make sure that you have the delegate correct or else it will not work.

Related

Expedia app sectionIndex: how they do that?

I noticed that Expedia app ( http://a5.mzstatic.com/us/r1000/027/Purple/4c/f4/6c/mzl.wcipbyyg.320x480-75.jpg) has a customized sectionIndex for UITableView on hotels list. (image attached)
I'm figuring that it could be a custom view, maybe with a vertical UISlider but, as I know, UISlider cannot recognize touch events on slides but just dragging ones.
So, how they do that ? A vertical sequence of buttons ? But, in this case, how to recognize dragging events ?
I would like to replicate that control but I need some hints ;)
thanks
There are more ways how to achieve the effect. Assuming you have a self.view initialized from a nib file and it's ordinary UIView, you can put this code into viewDidLoad:
- (void)viewDidLoad
{
CGRect tvFrame = self.view.frame;
tvFrame.origin = CGPointZero;
UITableView* tv = [[UITableView alloc] initWithFrame:self.view.frame];
tv.delegate = self;
tv.dataSource = self;
tv.showsVerticalScrollIndicator = NO;
[self.view addSubview:tv];
CGRect svFrame = CGRectMake(290, 10, 30, 400);
UIScrollView* sv = [[UIScrollView alloc] initWithFrame:svFrame];
sv.contentSize = CGSizeMake(10, 780);
sv.showsVerticalScrollIndicator = NO;
sv.bounces = YES;
CGRect vFrame = CGRectMake(10, 380, 10, 20);
UIView* v = [[UIView alloc] initWithFrame:vFrame];
v.backgroundColor = [UIColor blueColor];
[sv addSubview:v];
[self.view addSubview:sv];
[super viewDidLoad];
}
This will create a table with a narrow scroll view with a blue rectangle over the table. Now you can scroll both scroll views (the table is also a scroll view) independently.
Then you will have to setup delegates and receive scroll events via UIScrollViewDelegate. When one of the scroll views starts dragging, you have to start setting offset of the other scroll view.

Customizing UIPickerView (background and spacing)

I would like to change the white background in a UIPickerView to an image of my own.
Is this possible?
Also, I have managed to get my UIPickerView to scroll horizontally instead of vertical. Now, I would like to know if there is any way to adjust the spacing between two rows of the picker view?
I have attached an image to show what I mean.
This is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
arrayDays = [[NSMutableArray alloc] init];
[arrayDays addObject:#"ONSDAG"];
[arrayDays addObject:#"TORSDAG"];
[arrayDays addObject:#"FREDAG"];
[arrayDays addObject:#"LØRDAG"];
arrayDates = [[NSMutableArray alloc] init];
[arrayDates addObject:#"29. JUNI"];
[arrayDates addObject:#"30. JUNI"];
[arrayDates addObject:#"1. JULI"];
[arrayDates addObject:#"2. JULI"];
pickerViewDay = [[UIPickerView alloc] initWithFrame:CGRectZero];
[pickerViewDay setDelegate:self];
[pickerViewDay setShowsSelectionIndicator:NO];
CGAffineTransform rotate = CGAffineTransformMakeRotation(-M_PI/2);
rotate = CGAffineTransformScale(rotate, 0.25, 2.0);
[pickerViewDay setTransform:rotate];
[pickerViewDay setCenter:CGPointMake(self.view.frame.size.width/2, (pickerViewDay.frame.size.height/2)-3)];
[self.view addSubview:pickerViewDay];
// Adding selection indicator to pickerview
UIImage *selectorImage = [UIImage imageNamed:#"DayPickerView_SelectionIndicator.png"];
UIView *customSelector = [[UIImageView alloc] initWithImage:selectorImage];
[customSelector setFrame:CGRectMake(0, 0, 120, 74)];
[customSelector setCenter:CGPointMake(self.view.frame.size.width/2, customSelector.frame.size.height/2)];
[self.view addSubview:customSelector];
[customSelector release];
// Adding background to pickerview
UIImage *backgroundImage = [UIImage imageNamed:#"DayPickerView_Background.png"];
UIView *custombackground = [[UIImageView alloc] initWithImage:backgroundImage];
[custombackground setFrame:CGRectMake(0, 0, 320, 74)];
// [self.view addSubview:custombackground];
[custombackground release];
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
UIView *viewRow = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 80)];
CGAffineTransform rotate = CGAffineTransformMakeRotation(3.14/2);
rotate = CGAffineTransformScale(rotate, 0.25, 2.0);
// Date
CGRect rectDate = CGRectMake(30, 0, 150, 80);
UILabel *date = [[UILabel alloc]initWithFrame:rectDate];
[date setTransform:rotate];
[date setText:[arrayDates objectAtIndex:row]];
[date setFont:[UIFont fontWithName:#"Arial-BoldMT" size:37.0]];
[date setShadowColor:[UIColor whiteColor]];
[date setShadowOffset:CGSizeMake(0, -1)];
[date setTextAlignment:UITextAlignmentCenter];
[date setBackgroundColor:[UIColor clearColor]];
[date setClipsToBounds:YES];
[viewRow addSubview:date];
// Day
CGRect rectDay = CGRectMake(-30, 0, 150, 80);
UILabel *day = [[UILabel alloc]initWithFrame:rectDay];
[day setTransform:rotate];
[day setText:[arrayDays objectAtIndex:row]];
[day setFont:[UIFont fontWithName:#"Arial-BoldMT" size:21.0]];
[day setTextColor:[UIColor colorWithRed:0.35 green:0.35 blue:0.35 alpha:1]];
[day setTextAlignment:UITextAlignmentCenter];
[day setBackgroundColor:[UIColor clearColor]];
[day setClipsToBounds:YES];
[viewRow addSubview:day];
return viewRow;
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [arrayDays objectAtIndex:row];
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [arrayDays count];
}
EDIT 1
For RickiG (on background):
EDIT 2
For RickiG:
Hi
There is no direct way to change the background. What you can do is to have the view you return in viewForRow feature its own background (then add the shadow in each side afterwards if you need it). You can also go looking for viewWithTag: but that is never a good idea as this might change in future iOS releases.
Is there a special reason you implement both viewForRow and TitleForRow? I usually just populate the viewForRow's labels inside this delegate method.
The viewForRow has the ability to reuse the views in the Picker, much like a UITableView you should test if the "reusingView:(UIView *)view" is nil and if not there is no need to draw everything again. Just populate the labels.
I usually never customize the picker, if I need something not completely custom I subclass the UITableView, it is much more flexible and can what the Picker does + more.
For the spacing you can use the "height" of the rows, the picker will center the views you return in viewForRow, then just make sure:
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
returns a value bigger than your view.
Held og lykke;)
I just figured out how to apply background color or image in the picker view. Hope it may help someone.
Just define a category in the file where you want to you picker view as follow:
#implementation UIPickerView(Extension)
-(void)drawRect:(CGRect)rect
{
NSArray* subviews = [self subviews];
for(UIView* view in subviews)
{
if([view isKindOfClass:[UITableView class]])
{
view.backgroundColor = appColor;
}
}
[super drawRect:rect];
}
#end
You can look further at subviews for more customization.
Looks like this is an old thread, but in iOS 7 (Possibly earlier, I'm not sure), UIPickerViews have a background color property, so setting the background color is simple:
[pickerView setBackgroundColor:[UIColor whiteColor]];
Setting a background image is similarly simple thanks to [UIColor colorWithPatternImage:]. (Note that the pattern will tile if the image is smaller than the UIPickerView.)
[pickerView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"someBackgroundImage.png"]]];
To modify the component widths you can implement the delegate method widthForComponent in order to set various widths for each component. In theory, you should be able to add an empty component and use it's blank width to create spacing, but I haven't tried this.
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;
I haven't been able to find a way to change the padding between components which seems like a nicer way to modify the spacing and would also allows you to remove the ~5 px spacing between components, but if I'm able to find one I will update my answer.
How about adding an empty view on the right of your labels? And for the background you should probably use insertSubview:aboveView: method with the default background view as the second parameter (if you can access to it).

Changing bounds of imageView of UITableViewCell

I'm trying to place various size images inside imageView of UITableViewCell. I get the image data asynch'ly, create the image, set the content mode of imageView and finally set bounds of imageView. But the code seems insensitive to any changes I made. I want the images to be centered in a 75x75 area. I wrote the below code for this purpose
UIImage* image = [UIImage imageWithData:data];
[holder.imageView setContentMode:UIViewContentModeCenter || UIViewContentModeRedraw];
[holder.imageView setImage:image];
[holder.imageView setBounds:CGRectMake(0,0,75,75)];
[holder.imageView setFrame:CGRectMake(0,0,75,75)];
[holder setNeedsLayout];
Where holder is the UITableViewCell. The result I get is always the same. All images have 75px height and different widths. Can someone help me solve this problem?
I have realized that setting contentMode and bounds properties does not have any effect in that code. I have added an NSLog after the last line and got the results as below:
NSLog(#"imageview:%# bounds and contentMode:%# %#",[holder imageView],[holder.imageView bounds],[holder.imageView contentMode]);
imageview:<UIImageView: 0x39ab8a0;
frame = (0 0; 75 75); opaque = NO;
userInteractionEnabled = NO; layer =
<CALayer: 0x39a92b0>> bounds and
contentMode:(null) (null)
Still no solution
Done, I finally found the solution, it cost me 3 hours though =)
The solution is to change properties like bound,frame,contentMode in -(void)layoutSubviews method of the custom UITableViewCell class. The "trick" is to write layout code in this method, otherwise the code does not have any effect.
Below code did the work for me. It makes rows of the table vertically aligned.
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.bounds = CGRectMake(0,0,75,75);
self.imageView.frame = CGRectMake(0,0,75,75);
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
CGRect tmpFrame = self.textLabel.frame;
tmpFrame.origin.x = 77;
self.textLabel.frame = tmpFrame;
tmpFrame = self.detailTextLabel.frame;
tmpFrame.origin.x = 77;
self.detailTextLabel.frame = tmpFrame;
}
So the problem with UITableViewCell's is that you have no control over the size of the built-in objects (namely imageView, contentView, accessoryView, backgroundView). When the table changes, your customizations get trampled over.
You can, as Behlul pointed out, force the sizes to be correct by using layoutSubviews, but the problem with that is that layoutSubviews is called every time the table scrolls. That is a lot of unnecessary re-layout calls.
An alternate, method is to add all of your content to the contentView. Similarly if you are customizing the background, you can create a transparent backgroundView and add your custom background view (eg myBackgroundView) as a subview of backgroundView.
This way you can place and size your items how you want them.
The down side is the stock messages are no longer received from the accessory or image views. You just have to create you own.
Hope that helps!
// This code is not tested
// MyCustomTableViewCell
- (id) init{
self = [super initWithStyle: UITableViewCellStyleDefault reuseIdentifier:#"MyReuseIdentifier"];
if(self){
//image view
my_image_view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"default_image.png"]] retain];
[my_image_view setFrame:CGRectMake(10,10,30,30)];
[self.contentView addSubview:my_image_view];
//labels
my_text_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,10,100,15)] retain];
[self.contentView addSubview:my_text_label];
//set font, etc
//detail label
my_detail_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,25,100,15)] retain];
[self.contentView addSubview:my_detail_label];
//set font, etc
//accessory view
//Whatever you want to do here
//attach "accessoryButtonTapped" selector to button action
//background view
UIView* background_view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 50)] autorelease];
[background_view setBackgroundColor:[UIColor greenColor]];
background_view.layer.cornerRadius = 17;
background_view.layer.borderWidth = 3;
background_view.layer.borderColor = [UIColor whiteColor].CGColor;
[self setBackgroundView:[[[UIView alloc] init] autorelease]];
[self.backgroundView addSubview:background_view];
}
return self;
}
- (void) setLabelText: (NSString*) label_text{
[my_text_label setText:label_text];
}
- (void) setDetailText: (NSString*) detail_text{
[my_detail_label setText: detail_text];
}
- (void) accessoryButtonTapped{
//call table view delegate's accessoryButtonTappedForRowWithIndexPath method
}
"UIViewContentModeCenter || UIViewContentModeRedraw" is equivalent to 1. It's also not a bitfield. You want UIViewContentModeCenter.
UITableViewCell.imageView is managed by the cell. If you want custom layout, try adding a view to contentView (I'm guessing what you mean by "centered in a 75x75 area"):
UIImageView * iv = [[[UIImageView alloc] initWithImage:image] autorelease];
iv.frame = (CGRect){{0,0},{75,75}};
iv.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin| UIViewAutoresizingFlexibleRightMargin;
iv.contentMode = UIViewContentModeScaleAspectFit;
[holder.contentView addSubview:iv];
try changing the "contentMode" property of imageView to 'UIViewContentModeScaleAspectFit' or 'UIViewContentModeScaleAspectFill'
Create subclass of UITableViewCell:
#interface UITableViewCellSubClass : UITableViewCell
#end
#implementation UITableViewCellSubClass
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0,4,32,32);
self.textLabel.frame = CGRectMake(42,4,300,32);
}
#end

Need to override drawrect if your UIView is merely a container?

According to Apple's docs, "Subclasses need not override -[UIView drawRect:] if the subclass is a container for other views."
I have a custom UIView subclass that is indeed merely a container for other views. Yet the contained views aren't getting drawn. Here's the pertinent code that sets up the custom UIView subclass:
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
// Consists of both an "on" light and an "off" light. We flick between the two depending upon our state.
self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
self.onLight.backgroundColor = [UIColor clearColor];
self.onLight.on = YES;
[self addSubview:self.onLight];
self.offLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
self.offLight.backgroundColor = [UIColor clearColor];
self.offLight.on = NO;
[self addSubview:self.offLight];
self.on = NO;
}
return self;
}
When I run the code that displays this custom UIView, nothing shows up. But when I add a drawRect method...
- (void)drawRect:(CGRect)rect
{
[self.onLight drawRect:rect];
[self.offLight drawRect:rect];
}
...the subviews display. (Clearly, this isn't the right way to be doing this, not only because it's contrary to what the docs say, but because it -always- displays both subviews, completely ignoring some other code in my UIView that sets the hidden property of one of the views, it ignores the z-ordering, etc.)
Anyway, the main question: why don't my subviews display when I'm not overriding drawRect:?
Thanks!
UPDATE:
Just to make sure that the problem doesn't lie in my custom subviews, I added in a UILabel as well. So the code reads:
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
// Consists of both an "on" light and an "off" light. We flick between the two depending upon our state.
self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
self.onLight.backgroundColor = [UIColor clearColor];
self.onLight.on = YES;
[self addSubview:self.onLight];
self.offLight = [[[LoyaltyCardNumberView alloc] initWithFrame:frame] autorelease];
self.offLight.backgroundColor = [UIColor clearColor];
self.offLight.on = NO;
[self addSubview:self.offLight];
self.on = NO;
UILabel* xLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
xLabel.text = #"X";
[self addSubview:xLabel];
}
return self;
The "X" doesn't display either.
UPDATE 2:
Here's the code that invokes my custom UIView (OffOnLightView):
// Container for all of the OffOnLightViews...
self.stampSuperView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)] autorelease];
[self.view addSubview:self.stampSuperView];
// Draw the stamps into the 'stamp superview'.
NSInteger numberOfCardSpaces = (awardType == None) ? 3 : 10;
for (NSInteger i = 1; i <= numberOfCardSpaces; i++)
{
OffOnLightView* newNumberView = [[[OffOnLightView alloc] initWithFrame:[self frameForStampWithOrdinal:i awardType:awardType]] autorelease];
newNumberView.on = (i <= self.place.checkInCount.intValue);
newNumberView.number = [NSString stringWithFormat:#"%d", i];
[self.stampSuperView addSubview:newNumberView];
}
Your subviews should have their frame initialized to the bounds of the parent uiview. Subviews are in a different coordinate system that is relative to the frame of the parent.
self.onLight = [[[LoyaltyCardNumberView alloc] initWithFrame:self.bounds] autorelease];
You should never call -drawRect: manually. If you need to force a redraw, call -setNeedsDisplay.
I would start by debugging (breakpoint or NSLog()) in the -drawRect: methods of the two subviews you are adding to make sure they are actually performing their drawing.
Also note how you're making both subviews the full size (frame) of the containing view, and setting their background colours to clear. I'm going to guess this is intentional, but it's possible they are displaying, but you just can't see anything due to them having a transparent background.

An iphone uipickerview that rotates horizontally?

I've only seen it in a VERY few iPhone apps... but it looks like a picker that rotates left/right (instead of top/bottom).
They usually put it on 1 line of a tableView... to allow the user to quickly pick between a small number of choices (like 3-10).
How is that coded?
Continuing the answer by Dave DeLong I got it working like this......
In viewDidLoad i did this...
CGRect frame = horizontalPickerView.frame;
frame.size.width = 50;
frame.size.height = 216;
frame.origin.x=90;
frame.origin.y = 200;
horizontalPickerView.frame = frame;
horizontalPickerView.transform = CGAffineTransformMakeRotation(3.14159/2);
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
UILabel *lbl = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 30, 20)] autorelease];
lbl.transform = CGAffineTransformMakeRotation(-3.14159/2);
lbl.text = #"hi";
return lbl;
}
Hope this helps
Here you will find source code for Picker which is horizontally aligned.
You can do this by taking a regular UIPickerView, adjusting its width (via setFrame:), and then applying an NSAffineTransform to rotate it 90º. You'll then need to rotate each item in the picker 90º the other way.
It's a little tedious to do it properly, but it can be done.
#Madhup's code lead me in the general direction I wanted when I searched for the horizontal UIPickerView but I then realized the question asked wasn't really addressed so for anyone who was looking for a more suitable answer to the left-to-right rotation. The code in the answers I'd read were all to enable left-to-right swiping, causing the picker to push the labels/rows with higher values to the left of the view. Any ways here's my contribution:
In the viewDidLoad method:
yourPickerView.frame = frame;
yourPickerView.transform = CGAffineTransformMakeRotation(4.71238898); //Instead of rotating clockwise 90° we're rotating 90° counterclockwise. 4.71238898 being ≈270° in radians.
[self.view addSubview:self.picker];
self.yourPickerView.delegate = self;
self.yourPickerView.dataSource = self;
self.yourPickerView.showsSelectionIndicator = YES;
self.yourPickerView.userInteractionEnabled = YES;
The pickerView's method:
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 20, 20)] autorelease];
yourLabel.transform = CGAffineTransformMakeRotation(1.57079633); //Instead of rotating counterclockwise 90° we're rotating 90° clockwise 1.57079633 being ≈90° in radians.
yourLabel.font = [UIFont fontWithName:#"System-Bold" size:18]; //Your font here.
yourLabel.text = #"yourLabel's text"; //or like me [NSString stringWithFormat:#"%#, [yourArray objectAtIndex:row]]
yourLabel.backgroundColor = [UIColor clearColor];
return label;
}
Try a paged scrollview that has the items you want on one per page, and perhaps overlay an image above it if you want nicer graphics for your control, and only allow for horizontal scrolling (don't make the contentSize of the scrollview taller than the size of the actual view, and disable vertical scroll bouncing on the control).
You will have to create picker programitcally, so that you can create your own sized picker with CGRectMake(x, y, width, height) then, you will have to rotate it, but rotating it will also rotate in the Picker's dataSources methods, you will have to rotate the view inverse of picker's rotation, I am including code hopfully it will help
.....
...
...
NSArray *arr = [NSArray arrayWithObjects:#"1 mi", #"2 mi", #"5 mi", #"10 mi", #"15 mi", #"20 mi", #"25 mi",
#"30 mi", #"35 mi", #"40 mi", #"45 mi", #"50 mi", #"75 mi", #"99 mi", nil];
radiusDefaults = [[NSMutableArray alloc] initWithArray:arr] ;
radiusPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 100, 150)];
radiusPicker.delegate = self;
radiusPicker.dataSource = self;
radiusPicker.showsSelectionIndicator = NO;
//Resize the picker, rotate it so that it is horizontal and set its position
CGAffineTransform rotate = CGAffineTransformMakeRotation(-1.57);
rotate = CGAffineTransformScale(rotate, .1, .5);
CGAffineTransform t0 = CGAffineTransformMakeTranslation(-61, 0);
radiusPicker.transform = CGAffineTransformConcat(rotate,t0);
// [theNavigationBar.topItem setTitleView:radiusPicker] ;
UIView *pickerWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 215)];
[self.view addSubview:radiusPicker];
[radiusPicker selectRow:6 inComponent:0 animated:NO];
[radiusPicker release];
.....
.......
....
#pragma mark -
#pragma mark UIPickerView
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row
forComponent:(NSInteger)component reusingView:(UIView *)view{
UIView *viewForRow = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 70, 400)] autorelease];
UILabel *label;
UIFont *font = [ UIFont fontWithName:#"ArialRoundedMTBold" size:22];
label = [[[UILabel alloc] initWithFrame:CGRectMake(0, 20, 70, 350)] autorelease];
[label setText:[NSString stringWithFormat:#"%#", [radiusDefaults objectAtIndex:row]]];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor blueColor];
label.font = font;
label.backgroundColor = [UIColor clearColor];
// label.opaque = NO;
[viewForRow addSubview:label];
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57);
rotate = CGAffineTransformScale(rotate, 1, 6.5);
[viewForRow setTransform:rotate];
return viewForRow;
}
Try this->
Create Plain UIVew of size of UIPickerview, add picker on it.
set numberOfComponentsInPickerView = 1.
set componant width.
Then add small sub views on it to Hide rest of picker. Only rotating wheel of componant should visible.
Transform plain view to rotate it through 90 degree.
Make sure to apply tranform in:
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *lbl = nil;
if(view)
{
lbl = (UILabel *) [view viewWithTag:11];
}
else
{
view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
lbl = [[UILabel alloc] initWithFrame:CGRectMake(1, 0, 30, 30)];
lbl.tag = 11;
lbl.backgroundColor = [UIColor clearColor];
lbl.textAlignment = UITextAlignmentCenter;
lbl.font = [UIFont fontWithName:#"Helvetica-Bold" size:18];
lbl.transform = CGAffineTransformRotate(lbl.transform, M_PI +M_PI/2);
[view addSubview:lbl];
[lbl release];
}
lbl.text = [dataSourceArray objectAtIndex:row];
return view;
}
Now you can add palin view as a subview for horizontal picker on any view.
Have you ever considered taking a table view and rotating it?
Didn't think so. Go try that. :)