This post is something I’ve worked on for quite a while. One of the biggest challenges building HittaHem was the photo-mode. I wanted the images in full screen and of course I wanted the images to rotate as the iPhone was rotated. At first this seemed like a piece of cake, just return YES to the shouldAutorotateToInterfaceOrientation event! Sure, that does it, but I didn’t want the whole application to rotate because the rest of the UI didn’t look good that way.

Instead of redesigning the entire application just to support rotating images I decided to solve the problem myself. I’ve seen other people ask how to accomplish this on other blogs etc so I know I’m not the only stupid person who thinks it’s a good idea to only rotate a part of the application. I did ask the Italian evangelist person at the iPhone Tech Talk World Tour if there really wasn’t an easier way to do it, his response was “why would you want to do that?”. I tried to explain but apparently it didn’t make sense to him. At least I knew I wasn’t a complete fool investing hours on rewriting something that could be done with one line of code. Facebook rotates the images in the albums without rotating the entire app, and Facebooks (as my mom calls it), can’t be idiots, right?
Instead of pasting tons of code here I’ll try to explain my solution and the biggest problems implementing it. As usual you’ll find a complete demo project at the end of the post.
The easiest way to know if the device is rotated is to listen to the shouldAutorotateToInterfaceOrientation event. But instead of returning YES and rotate the entire app, I forward the event to the superview before returning NO. The superview, in this case the image gallery, can then decide how to rotate its content to fit the new orientation. I place all my images inside a UIScrollView using the PageControl code from Apple. So what happens when the device is rotated? This image is very important:

It shows origo (or 0,0) position on the screen in UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait and UIInterfaceOrientationLandscapeLeft.
Portrait mode
The images are positioned next to each other following the x-axis. The width of the content in the UIScrollView equals the width of one image multiplied by the number of images. So if we have 6 images the contentSize of the UIScrollView is the same height as the screen and the width is 6 times the width of the screen. Height=480 Width=(320*6)=1920. The position of the leftmost image is 0,0.
UIInterfaceOrientationLandscapeRight
LandscapeRight is the “easy” rotation because the images are positioned almost like portrait mode, the difference being they are positioned over the y-axis instead of x. Again if we have 6 images the contentSize of the UIScrollView is the same height as the screen width and the width is 6 times the height of the screen. Height=320 Width=(480*6)=2880. The position of the leftmost image is 0,0.
UIInterfaceOrientationLandscapeLeft
This is where it gets a bit tricky. Because we still want the images positioned from left to right and the 0,0 point is now in the top right corner. If we were to position the images following the y-axis as in LandscapeRight the image positions would be reversed. The first image must be positioned at the highest y-axis value. Same example with 6 images: The leftmost image will be positioned at the screen width multiplied by 5, X=0 Y=5*480. The rightmost image is positioned at 0,0.
Here’s the code to calculate the correct position:
-(CGRect)calculateFramePosition:(CGRect)frame page:(int)page
{
// Calculate frame position depending on the interface orientation
if(currentOrientation == UIInterfaceOrientationLandscapeLeft)
{
frame.origin.x = 0;
frame.origin.y = frame.size.height * ([self.viewControllers count]-1 - page);
}
else if(currentOrientation == UIInterfaceOrientationLandscapeRight)
{
frame.origin.x = 0;
frame.origin.y = frame.size.height * page;
}
else
{
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
}
return frame;
}
The actual rotations are done by the UIView inside the UIScrollView. The view inside the scrollview just holds an UIImage that I’ve subclassed to support taps. The rotations are simple PI rotations using CGAffineTransformMakeRotation. Code:
-(void)rotate:(CGFloat)angle
{
portraitImageView.transform = CGAffineTransformMakeRotation(angle);
CGRect frame = portraitImageView.frame;
frame.origin.y = 0;
frame.origin.x = 0;
frame.size.width = portraitImageView.frame.size.height;
frame.size.height = portraitImageView.frame.size.width;
portraitImageView.frame = frame;
}
Here’s a video of the demo application. It’s using static images bundled with the app and can easily be changed to download images from the internet. Check out my post on downloading images asynchronously. I’ve done my best to add useful comments along with the code but if you have questions don’t hesitate to post a comment below. The code is free to use as you see fit, the only thing I ask is that you don’t publish it as your own and if you found it usefull: add a link to this blog from your site.
Download example project