2013-10-04 3 views
1

Недавно я задал аналогичный вопрос о том, как добавить полупрозрачный эффект в 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]; 
} 

Как я могу получить фон, чтобы следить за анимацией?

ответ

2

Я думаю, что проблема заключается в том, что как только вы меняете изображение, вызывается 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]; 
} 
+0

Однако я хочу, чтобы размытие было живым/актуальным с анимирующим фоном, поэтому я заставляю 'updateViewBG' получать вызов в надежде, что он будет соответствовать фону. –

+1

Я вижу. Тогда вам нужно будет обернуть 'layer.contents = ...' ('updateViewBG') в' CATransaction', чтобы вы могли установить неявную продолжительность анимации. Скорее всего, изменения не будут такими резкими, и все будет хорошо выглядеть. Если это не сработает, вы можете попробовать с помощью 'CABasicAnimation'. – sergio

+0

@LlamaGoingNorth: у вас были какие-то успехи в CATransaction? – sergio

Смежные вопросы