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

标签 ios objective-c uiview uiimageview gpuimage

我最近问了一个关于如何给 UIView 添加半透明效果的类似问题,得到了很好的回应。

但是它使用了大量的 CPU 处理能力,所以我使用了答案背后的一些想法,但使用效率更高的 GPUImage 进行了过滤。

它适用于静态屏幕,但我想用动画更改背景 UIImageView 的图像。但是,当我将 UIView 设置为在过渡期间对背景进行采样时,它似乎忽略了过渡并在动画开始之前显示新图像。
相关代码如下(需不需要再追问!):

包含自定义 UIViewUIImageView 背景的 super View :

//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];
}];

然后在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];
}

如何让背景跟随动画?

最佳答案

我认为问题在于,一旦您更改图像,就会调用 displayLayer(忽略正在进行的过渡),因此新图像将用于半透明。

您应该修改 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];
}

关于ios - 在 UIView 后面捕获(动画)屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19188489/

相关文章:

ios - 当我尝试将更长的文本放入其中时,UILabel 文本重置为非常小的字体大小

objective-c - 使用 Storyboard在 iPAD 上支持多个方向的最佳方法(无 AutoLayout 或 AutoResizing)

ios - iTunes Connect、TestFlight 和 Jenkins

ios - 禁用点击事件但不在 UIScrollView 上滚动

ios - 雅虎 OAuth 错误 401 消费者 key 未知

ios - 将 UIView 保存为 xml

ios - UIView:如何在调用 initWithFrame 之前设置属性?

ios - 如何更改 "...Would Like To Access Your Photos"对话框弹出框的背景颜色?

ios - 'SpringBoard' 可能不会响应 presentViewController

objective-c - viewDidAppear 中的动画