Недавно я задал аналогичный вопрос о том, как добавить полупрозрачный эффект в UIView и получил хороший ответ.Захват (анимированный) экран за UIView
Однако он использовал много процессорной мощности для обработки, поэтому я использовал некоторые идеи, лежащие в основе ответа, но сделал фильтрацию с использованием GPUImage, который намного эффективнее.
Это хорошо работает для статического экрана, но я хочу изменить фоновое изображение UIImageView
с анимацией. Однако, когда я устанавливаю UIView
, чтобы пробовать фон во время перехода, он, кажется, игнорирует переход и показывает новое изображение до начала анимации.
Соответствующий код выглядит следующим образом (спросите, если вам нужно больше!):
SuperView, содержащий пользовательские UIView
и UIImageView
фон:
//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];
}
Как я могу получить фон, чтобы следить за анимацией?
Однако я хочу, чтобы размытие было живым/актуальным с анимирующим фоном, поэтому я заставляю 'updateViewBG' получать вызов в надежде, что он будет соответствовать фону. –
Я вижу. Тогда вам нужно будет обернуть 'layer.contents = ...' ('updateViewBG') в' CATransaction', чтобы вы могли установить неявную продолжительность анимации. Скорее всего, изменения не будут такими резкими, и все будет хорошо выглядеть. Если это не сработает, вы можете попробовать с помощью 'CABasicAnimation'. – sergio
@LlamaGoingNorth: у вас были какие-то успехи в CATransaction? – sergio