b2cloud

8th September 2012

Snapshotting a view on iOS

Guides | Tutorial By 4 years ago

Snapshotting can be used on iOS to draw a view into an image, like a screenshot. Doing so is very beneficial in some scenarios such as smooth interface rotations and advanced animations.

Creating a snapshot is done via a CGContext with the following code:

//	Begin the image context
UIGraphicsBeginImageContextWithOptions(view.frame.size,	//	same size as our view
					NO,		//	transparent background (!opaque)
					0);		//	screen scale, 0 = main screen scale
CGContextRef ctx = UIGraphicsGetCurrentContext();

//	Translate to our active region, for example, where the content currently is in a scroll view
CGContextTranslateCTM(ctx, -view.bounds.origin.x, -view.bounds.origin.y);

//	Draw the view's layer
[view.layer renderInContext:ctx];

//	Grab the image
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();

//	End the image context (and clean up)
UIGraphicsEndImageContext();

Easy enough. Typically this should only be done on the main thread; if the main thread is drawing your views to the screen and one of your threads is drawing views to an image there could be some clashes. Having said this, I have found it safe to do this on a thread under the condition that it is done before the run loop ends (but test this thoroughly). For example if you needed to make a lot of these snapshots, you could spawn X threads and draw them asynchronously and then halt the main thread until all the drawing was finished. Note that if you ever do drawing on a thread, instead of using UIGraphicsGetCurrentContext you must create your own context.

In iOS7 this got even easier. There were 3 methods added to the UIView interface that will create snapshots faster than the older renderInContext: method.

If you simply want to visually create a copy then show the copy on screen, you can spawn a ‘replica’ static snapshot view, and set it’s frame and add it as a subview as you would any other view. This is done with the snapshotViewAfterScreenUpdates: method.

UIView* viewToCopy = ...;

UIView* snapshotView = [viewToCopy snapshotViewAfterScreenUpdates:YES];
[self.view addSubview:snapshotView];

There’s a similar method which instead creates a resizable snapshot, via resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:.

If you need a UIImage version like in the above CGContextRef example, simply replace the [view.layer renderInContext:ctx]; line with the following:

//	Draw the view's layer
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];

So with this knowledge and a bit of work, you can create animations such as the springboard split folder animation:

  • James Bush

    Tip: change the name of the UIView view in the first block of sample code to snapshotView or viewToCopy, whichever it may be (I haven’t figured that out yet…).

    • James Bush

      One more thing: I got it to work with this…

      – (UIImage *)snapshotImage:(UIView *)view
      {
      UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
      [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();

      return image;
      }

Recommended Posts

Learn C blocks in 20 seconds

Post by 4 years ago

Since the introduction of iOS4, blocks have become very prevalent in the Cocoa framework as a quick and non messy way of implementing a 'callback'. Blocks can be passed around just like any other variable....

Got an idea?

We help entrepreneurs, organizations and established brands from around
the country bring ideas to life. We would love to hear from you!