views:

3752

answers:

4

I am attemting to transition from one UIView to another, when the user rotates the device. This, in of itself, is not difficult. However, since I am displaying completely different content after the rotation, the default animation provided by UIKit (rotating the currently displayed view) is inappropriate conceptually.

Simply disabling the animation and swapping the views suddenly is tolerable, but is far below the polish I'm building into the rest of the app. What I would prefer to do is this:

When shouldAutorotateToInterfaceOrientation: is called, I would like to grab an opaque view snapshot, a screenshot if you will, of the user view before rotation. Then after the rotation is completed and the system has applied the view transforms etc, I can show the snapshot view I saved and animate a transition of my choice to my new view. After it is completed, I can release my snapshot and move on.

Is there a way to do this that is not expensive?

The only other option I can think of is to return NO on all orientations other than my default one, and then react by applying my own animations and transforms. I'd prefer to use the system to do this however, as I feel it is likely doing it myself could cause "undefined" keyboard behavior in the manually rotated view, etc.

Thoughts?

+4  A: 

On Mac this is so easy... you just need -bitmapImageRepForCachingDisplayInRect:, but of course iPhone has no such thing.

I think I would attack this by setting up a graphics context and calling [window drawRect:...] on it to capture the current image of the screen. This is a bit out of spec, because you're not really supposed to go calling -drawRect: yourself. I'd be a bit nervous of side-effects on doing this, but it may be fine. If it's a full-screen view you control, you could of course hoist the drawing code out of -drawRect: so you're not calling that directly.

A similar approach would be to use CALayer -drawInContext: of the current -presentationLayer. That might be slightly more "in spec" since it's legal to pass that your own context. But I don't know if you'd actually be able to get all the sub-views correctly. Might depend on the nature of your UIWindow.

Anyway, great question. Maybe someone has a more clever solution, but this is the way I'd attack it.

EDIT: Thanks to Rob Terrell, and his clever UIApplication+TVOut.m, I was introduced to the private method UIGetScreenImage() which returns a CGImageRef. If you're willing to go to private methods, that's a nice option for you. Given its name and functionality, it looks pretty stable to me and seems unlikely to violate Apple's intent. I also bumped into a pretty nice discussion on Air Source. Read through the comments for several links.

Rob Napier
A: 

I can guarantee you [window drawRect:] won't work. Most views don't implement drawRect: and it's certainly not recursive like on the mac.

drawInContext: is also pretty much hosed simalarly, as it's fundamentally asking the layer to draw itself, not its sublayers recursively. "Default implementation does nothing." says it all.

I implementing this for the Clif Bar Save Our Snow app in the app store by doing the following:

  • Walk the layer hierarchy recursively, getting the contents from each layer. If it smells like an image, use the CGContext methods to draw it into your context.
  • While walking, make sure to apply the transformations/positions of each layer as you call recursively

Yes, a rather large pain in the ass. But yes, it works pretty well and got through by Apple :).

Andrew Pouliot
A: 

If you want to publish on the App Store, using UIGetScreenImage() will get your app rejected.

Todd Hopkinson
+1  A: 
  • (UIImage *)captureView:(UIView *)view { CGRect screenRect = [[UIScreen mainScreen] bounds];

    UIGraphicsBeginImageContext(screenRect.size);

    CGContextRef ctx = UIGraphicsGetCurrentContext(); [[UIColor blackColor] set]; CGContextFillRect(ctx, screenRect);

    [view.layer renderInContext:ctx];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage; }

Found this here :

http://discussions.apple.com/thread.jspa?messageID=8358740

Sunil Phani Manne