简体   繁体   English

在UIView后面捕获(动画)屏幕

[英]Capturing (animated) screen behind UIView

I asked a similar question recently on how to add a translucent effect to a UIView and got a good response. 最近我问了一个类似的问题,关于如何向UIView添加半透明效果,并获得了很好的答复。

However it used a lot of CPU power to process so I used some of the ideas behind the answer but did the filtering using GPUImage which is much more efficient. 但是,它使用了大量的CPU能力进行处理,因此我使用了答案背后的一些想法,但是使用了效率更高的GPUImage进行了过滤。

It works well for a static screen, but I want to change the background UIImageView 's image with an animation. 它适用于静态屏幕,但是我想用动画更改背景UIImageView的图像。 However when I set the UIView to sample the background during the transition, it seems to ignore the transition and show the new Image before the animation has started. 但是,当我将UIView设置为在过渡期间对背景进行采样时,似乎会忽略过渡并在动画开始之前显示新的Image。
The relevant code is as follows (ask if you need more!): 相关代码如下(如果需要更多,请询问!):

The superview containing the custom UIView and the UIImageView background: 包含自定义UIViewUIImageView背景的超级视图:

//The Transition
[contentView setScheduled:YES]; //Starts the sampling every 0.2 seconds

//bg is the UIImageView and contentView is the 'translucent' UIView subclass
[UIView transitionWithView:bg duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    [bg setImage:newImage];
}completion:^(BOOL finished){
    [contentView setScheduled:NO];
}];

Then in the UIView subclass: 然后在UIView子类中:

- (UIImage *)snapshotOfSuperview:(UIView *)superview
{
CGFloat scale = 0.5;
if (([UIScreen mainScreen].scale > 1 || self.contentMode == UIViewContentModeScaleAspectFill))
{
    CGFloat blockSize = 12.0f/5;
    scale = blockSize/MAX(blockSize * 2, floor(self.blurRadius));
}
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, -self.frame.origin.x, -self.frame.origin.y);
self.hidden=YES; //Don't take a snapshot of the view
[superview.layer renderInContext:context];
self.hidden=NO;
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshot;
}

-(void)updateViewBG{
UIImage *superviewImage = [self snapshotOfSuperview:self.superview];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    GPUImageGaussianBlurFilter* filter = [[GPUImageGaussianBlurFilter alloc] init];
    filter.blurSize = 0.8f;
    UIImage* newBG = [self applyTint:self.tintColour image:[filter imageByFilteringImage:superviewImage]];

    dispatch_async(dispatch_get_main_queue(), ^{
        self.layer.contents = (id)newBG.CGImage;
        self.layer.contentsScale = newBG.scale;
    });
});
}

-(UIImage*)applyTint:(UIColor*)colour image:(UIImage*)inImage{
UIImage *newImage;
if (colour) {
    UIGraphicsBeginImageContext(inImage.size);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, inImage.size.width, inImage.size.height);

    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);
    CGContextSaveGState(ctx);
    CGContextClipToMask(ctx, area, inImage.CGImage);
    [colour set];
    CGContextFillRect(ctx, area);
    CGContextRestoreGState(ctx);
    CGContextSetBlendMode(ctx, kCGBlendModeLighten);
    CGContextDrawImage(ctx, area, inImage.CGImage);
    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}else{
    newImage = inImage;
}
return newImage;
}

-(void)displayLayer:(CALayer *)layer{
[self updateViewBG];
}

How can I get the background to follow the animation? 如何获得背景以跟随动画?

I think the problem is that as soon as you change the image, displayLayer is called (disregarding the transition being in progress) and thus the new image is used for the translucency. 我认为问题在于,一旦更改图像,就会调用displayLayer(不考虑进行中的过渡),因此新图像将用于半透明。

You should modify updateViewBG so that it does not update the layer content before the transition is finished. 您应该修改updateViewBG以便它不会在过渡完成之前更新图层内容。 Eg, you could add a flag to your class, set it when you start the transition and reset it when it completes. 例如,您可以将标记添加到类中,在开始转换时进行设置,并在转换完成时将其重置。 When the flag is set you do not call updateViewBG . 设置标志后,请勿调用updateViewBG

[UIView transitionWithView:bg duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{

    self.isTransitionInProgress = YES;
    [bg setImage:newImage];

}completion:^(BOOL finished){

    [contentView setScheduled:NO];

    self.isTransitionInProgress = NO;
    [contentView.layer setNeedsDisplay];

}];



-(void)displayLayer:(CALayer *)layer{
    if (!self.isTransitionInProgress)
        [self updateViewBG];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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