Sunday, January 4, 2009

Auto-rotating Tab Bars on the iPhone

This post is a quick summary of what's needed to get a tab bar (like the one in the Clock application) to switch from portrait to landscape when the user rotates their phone. Accelerometer goodness, yum!

The process is easy, but it has a couple of pitfalls. Here are the steps:
  1. You have to override shouldAutorotateToInterfaceOrientation: in the view controllers for all the views in the tab bar. If a view controller's shouldAutorotateToInterfaceOrientation: returns NO, then the tab bar will not rotate, even if the view is hidden at the time of the rotation.
  2. You should not override the tab bar controller's version of shouldAutorotateToInterfaceOrientation:
  3. For regular views in the tab bar add the code below to viewDidLoad. If you skip this, your view will not resize when the phone is rotated while it's selected. However, it will resize when the user transitions to it from another view.

  4. Make sure the controls on your regular views respond to changes in view size. If you're using Interface Builder's springs and struts, you can test the views right in IB, using the arrow at the right of the views' title bars.
Acknowledgements: I used the knowledge in some forum posts that Google revealed to me, together with some testing.

I hope you found this useful. If you have more tips, please post them in the comments, and I'll edit the posting accordingly, so others can have an easier time finding this information.

12 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. [I apologize for leaving/deleting multiple, no way to edit comments apparently]

    Hey Victor, thanks for posting this. I'm curious why you advise not to override the UITabBarController's shouldAutoRotate... method? I feel like the SDK is lacking in this regard - what if you have a view controller in one tab that you want to rotate, but others you do not want to rotate? Shouldn't UITabBarController's shouldAutoRotate method go something like:

    return [self.selectedViewController shouldAutoRotateToInterfaceOrientation:interfaceOrientation];

    This way it would respect the autorotation wishes of whichever UIViewController is currently selected. Curious about your feedback.

    ReplyDelete
  3. @Andy

    While debugging this problem, I found that the UITabController's shouldAutoRotateToInterfaceOrientation: method calls the same method in all the view controllers under the tab view (at least in 2.2).

    I think it's a bad idea to override the tab controller's method because, when I did that, the tab view rotated together with the sub-views, but the sub-views' layout was not recomputed. So the sub-views did not become "wide".

    Regarding your situation... I hope you have good reasons for supporting auto-rotation only in some views. As a user, I wouldn't be very happy if I were in a wide view, clicked on a tab, and the tab bar suddenly disappeared from under my fingers.

    ReplyDelete
  4. Victor, I have been trying to get my tab bar to rotate for a week now without being successful, even after reading this article. Could you post an xcode project containing a working implementation of an auto-rotating tab bar?

    ReplyDelete
  5. Nice post - this was exactly what I needed! My tab controller was rotating but the views inside were not, and the code you suggested adding to viewDidLoad did the trick.

    ReplyDelete
  6. finally! some good info on this topic. i was having trouble with the views not expanding horizontally and the viewDidLoad lines above finally fixed it.

    ReplyDelete
  7. Great post - thank you.
    I am having the issue of auto rotate the table view.
    For some reason, the rows wont get rotated until I scroll it up or down.

    I guess "ViewDidLoad" only fire once. That might be an issue.

    Does any one has an idea why?

    Thank you,

    ReplyDelete
  8. Item 3 refers to "code below" but I cannot see any code below.

    ReplyDelete
  9. thankyou so much for those two lines of code!!! you dont know how frustrating that resize issue was!!

    ReplyDelete
  10. Thanks!!!

    self.view.autoresizesSubviews = YES;
    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    Is the key :-)

    ReplyDelete