Using UIDatePicker in landscape mode

We've come up with a workaround for using the iPhone UIDatePicker class in landscape mode.

In our development work for Life Balance, I ran into a problem with the UIDatePicker class on iPhone OS 3.1.2. If you put an application in landscape mode, and then open a view containing a UIDatePicker, the picker is shifted to the right. If you set the background of the UIDatePicker to red to help visualize the problem, it looks like this:

Searching the Apple Developer Forums and the internet at large didn't turn up any good solutions, so I started my own investigation. The fix turns out to be pretty easy, once you delve deep enough into UIDatePicker to understand what the problem is.

UIDatePicker contains a UIPickerView as a subview. When you initialize a UIDatePicker it sets the frame of the subview based on the current screen orientation. If the device is in landscape mode, it sets this frame to create a landscape mode picker, even though the surrounding view is still configured for portrait mode. Once this happens, the built-in autoresizing mask guarantees that the subview will stay messed up no matter what you do to the UIDatePicker.

To correct the problem, all you have to do is fix the frame of the subview once, and it will stay fixed.

The easiest fix is probably to repair the UIDatePicker in the loadView method of your view controller, like this:

- (void) viewDidLoad {
    [super viewDidLoad];
    for (UIView * subview in datePicker.subviews) {
        subview.frame = datePicker.bounds;
    }
}

With this fix, the UIDatePicker will display identically in portrait and landscape modes:

If you use lots of date pickers in your code, it might be worthwhile to create a subclass of UIDatePicker that handles the repair automatically.

 

RotatingDatePicker.h

#import <UIKit/UIKit.h>
@interface RotatingDatePicker : UIDatePicker {
}
@end

RotatingDatePicker.m

#import "RotatingDatePicker.h"

@implementation RotatingDatePicker

- (id)initWithFrame: (CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        for (UIView * subview in self.subviews) {
            subview.frame = self.bounds;
        }
    }
    return self;
}

- (id) initWithCoder: (NSCoder *)aDecoder {
    if (self = [super initWithCoder: aDecoder]) {
        for (UIView * subview in self.subviews) {
            subview.frame = self.bounds;
        }
    }
    return self;
}

@end

If you go with the subclass option and you create your views in NIB files, you don't have to change your code at all. You just have to change the class of your date pickers in your NIB files to RotatingDatePicker.

An added bonus of this fix is that it lets you use the alternative 480 x 162 size of picker when you are in landscape mode, although you don't have to. I don't think there's any way of getting the alternate size using the autoresizing mask, but you can get it by having your view controller layout the view manually:

- (void) arrangeViews: (UIInterfaceOrientation)orientation {
    if (UIInterfaceOrientationIsPortrait(orientation)) {
        datePicker.frame = CGRectMake(0, 0, 320, 216);
    }
    else {
        datePicker.frame = CGRectMake(0, 0, 480, 162);
    }
}

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear: animated];
    [self arrangeViews:
          [UIApplication sharedApplication].statusBarOrientation];
}

- (void) willAnimateRotationToInterfaceOrientation:
                          (UIInterfaceOrientation)interfaceOrientation
         duration: (NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation: interfaceOrientation
                                            duration: duration];
    [self arrangeViews: interfaceOrientation];
}

With both the bug fix and the rotation code in place, you can have good looking date pickers in all orientations.


Copyright @ 2009, Stuart A. Malone, permission is granted for this article to be redistributed and shared with others in its entirety as long as links and attribution are maintained.

Stuart A. Malone is Chief Technology Officer of Llamagraphics, Inc., developer of Life Balanceā„¢ software for Mac OS X, Windows, Palm OS and iPhone. Life Balance provides a structure for your goals, projects and tasks that is priority driven, so you can to make better decisions about how to use your discretionary time. To learn more, please visit http://www.llamagraphics.com/

Comments

Amazing!

You are genius!!!!!
My layout works like charm now,

Thank you very mutch!

Elegant solution

Such a simple and elegant solution. I've been banging my head against the wall on this for the past week. Thank you for sharing!

Great

Thank u

great

super guy ... i hit my head for a couple of days before running into your great post.
thanks a lot

A great big thanks !!!!

This completely and very elegantly fixes this issue !
The kind of thing I always strive to do.
I often see people write hundreds of lines of code to do such things when often there is a cleaner better way like this.

Very Helpful

I ran into this exact problem and this solved it right away. Many thanks.

A Billion Thanks

So much better than the solution I'd been using of creating the date picker when the app launched.

Syndicate content