Taking a snapshot of a CATiledLayer-enabled image in UIScrollView

I have a custom map view that is made from UIScrollView. Scrolling view preview supported CATiledLayer. Everything works fine here. Panning and zooming load new maps, and everything works well.

What I want to do is to capture the frames of the video animation into this scroll view. Essentially, I want to create a video of animated changes in the form of scroll contentOffsetand zoomScale.

I know the concept sounds like I can get a private API function UIGetScreenImage()to capture an application screen, say 10 frames per second, combine these images, and I get a playback animation that is smooth and uses timelines using scroll animation.

My problem, of course, is that I cannot use a private API. Passing the alternatives described by Apple here leaves me with quite a few acceptable options: ask CALayerbefore renderInContextand take UIGraphicsGetImageFromCurrentImageContext()from it.

This does not seem to work with CATiledLayer-backed views. A blocky, not enlarged image is what is captured, as if tiles with a higher resolution never load. This makes some sense, given that it CATiledLayeruses background threads for performance, and a call renderInContextfrom the main thread might not catch these updates. The result is similar even if I create a tiled layer presentationLayer.

Is there any way Apple authorized the capture of a CATiledLayer-backed view image while watching a scroll animation? Or at any moment, for that matter?

+5
source share
3 answers

By the way, this is doable if you correctly implement -backed renderLayer:inContext:in your view CATiledLayer.

+1

renderInContext: , , . ?

0

This code works for me.

- (UIImage *)snapshotImageWithView:(CCTiledImageScrollView *)view
{
// Try our best to approximate the best tile set zoom scale to use
CGFloat tileScale;
if (view.zoomScale >= 0.5) {
    tileScale = 2.0;
}
else if (view.zoomScale >= 0.25) {
    tileScale = 1.0;
}
else {
    tileScale = 0.5;
}

// Calculate the context translation based on how far zoomed in or out.
CGFloat translationX = -view.contentOffset.x;
CGFloat translationY = -view.contentOffset.y;
if (view.contentSize.width < CGRectGetWidth(view.bounds)) {
    CGFloat deltaX = (CGRectGetWidth(view.bounds) - view.contentSize.width) / 2.0;
    translationX += deltaX;
}
if (view.contentSize.height < CGRectGetHeight(view.bounds)) {
    CGFloat deltaY = (CGRectGetHeight(view.bounds) - view.contentSize.height) / 2.0;
    translationY += deltaY;
}

// Pass the tileScale to the context because that will be the scale used in drawRect by your CATiledLayer backed UIView
UIGraphicsBeginImageContextWithOptions(CGSizeMake(CGRectGetWidth(view.bounds) / view.zoomScale, CGRectGetHeight(view.bounds) / view.zoomScale), NO, tileScale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, translationX / view.zoomScale, translationY / view.zoomScale);

// The zoomView is a subview of UIScrollView. The CATiledLayer backed UIView is a subview of the zoomView.
[view.zoomView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;

}

The full example code is found here: https://github.com/gortega56/CCCanvasView

0
source

All Articles