简体   繁体   中英

How to correctly use renderInContext in a completion block?

My view/layer hierarchy looks like this:

CustomUIView  [A]
  |
  +--- UIImageView [B]

When the UI is first displayed, view [B] shows a default image (a game board).

In reaction to a user event I create a few CALayer objects and add them as sublayers to view [A] 's backing layer. I then use them to render an animation, optically changing parts of the game board, because hierarchically they are on top of the image view. This works just fine.

Once the animation completes, I want to take a screenshot of the resulting layer state, set that as the new image of [B] and then discard the temporary sublayers before the next move in the game.

My code looks like this:

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    UIImage *snapshot = [self.view snapshot];
    self.snapshotVIew.image = snapshot;
    for (CALayer *tileLayer in tempLayers)
    {
        [tileLayer removeFromSuperlayer];
    }
}];

CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations =@[contentAnimation, zoom];
animGroup.duration = 0.5f;
animGroup.removedOnCompletion = NO;
animGroup.fillMode = kCAFillModeForwards;
for (CALayer* tileLayer in tempLayers)
{
    [tileLayer addAnimation:animGroup forKey:nil];
}
[CATransaction commit];

The snapshot method of my custom view is pretty standard:

- (UIImage*) snapshot {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, [[UIScreen mainScreen] scale]);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}

The problem seems to be that renderInContext 's documentation says:

Renders the receiver and its sublayers into the specified context. This method renders directly from the layer tree, ignoring any animations added to the render tree .

Because of that last highlighted sentence, once the layers have been removed, everything looks as it did before. Apparently, when the completion block runs, the layer tree does not seem to have been updated with the finished animation state, so my screenshot does not take that into account.

How would I go about doing this?

Try rendering the layer's presentationLayer:

[self.layer.presentationLayer renderInContext:UIGraphicsGetCurrentContext()];

Alternately, instead of using removedOnCompletion = NO, set your layers' properties to their final states after adding the animations. Then when the animation completes, the layer WILL reflect the changed appearance, and you can render the normal layer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM