对于整个iOS 7的感觉,我想对屏幕的特定部分应用模糊效果来对其进行模糊处理,但我不想立即抛出模糊,我想要将其设置为动画并设置动画它出来,所以用户几乎看到了应用的模糊效果。
几乎就像在Photoshop中一样,你将高斯模糊值从0改为10,而不是一次性改为0到10。
我已经尝试了一些解决方案,最流行的建议是简单地将模糊视图放在非模糊视图的顶部,然后降低模糊视图的alpha值。
这可以好的,但不是很赏心悦目,因为没有过渡,它只是一个叠加。例如:
实现这种效果的更好方法是什么?我熟悉GPUImage,但不知道如何用它完成它。
如果我可以控制它的模糊百分比,那也很棒,所以它可以从用户交互式地应用。 (例如:用户拖动中途,模糊一半,等等。)
答案 0 :(得分:44)
使用iOS 9及更高版本,您可以为视觉效果视图设置动画效果:
[UIView animateWithDuration:0.3 animations: ^ {
visualEffectView.effect = blurEffect;
} completion:nil];
这将实现动画模糊半径的预期效果。
我认为如果您从非模糊视图中设置交叉渐变动画 - >模糊的看法,这将是令人愉快的。您需要在非模糊视图的顶部为模糊视图的显示设置动画。
我们假设blurView
是包含模糊效果的视图。
以下是如何完成动画过渡的两个示例:
[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
[self.view addSubview:blurView];
} completion:nil];
这里我假设已经设置了blurView
,只是将动画中的添加转换为子视图。
您也可以通过不同的方式实现这一目标:
blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
blurView.alpha = 1.0f;
} completion:nil];
在这里,我将模糊视图设为透明并为其外观设置动画。请注意,使用此方法不适用于hidden
,因此您希望使用alpha
属性。
如果您希望以交互方式控制模糊量,以下是如何实现的示例:
首先创建要模糊的视图的图像:
UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
保留此图片。如果视图已更改,您只想以类似的方式重绘。否则,您应该重复使用此图像,因为绘制层次结构的成本很高。
现在,当您需要模糊时,请使用以下代码:
CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"];
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"];
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];
inputRadius
输入可设置执行的模糊量。如果你动画这个,你将获得互动的感觉。
但我仍然认为前一种方法更容易,并且对用户也感觉良好。
答案 1 :(得分:6)
在OS X上这很容易,其中一个视图可以对其后面的视图产生影响,并且处理器功能强大且速度快。然而,在iOS上,没有视图合成滤镜,模糊需要一些时间:你不能像动画的帧那样重复,实时地进行。因此需要某种形式的妥协。
如果你事先知道你想要模糊的东西,你可以使用渐变的模糊来准备一系列图像:没有模糊,有点模糊,有点模糊,等等。然后你组装图像和"播放"他们作为"框架"一个动画的UIImageView。
然而,这不是我实际建议的。我要做的是准备模糊图像和非模糊图像,并使用CIDissolveTransition从非模糊图像溶解到模糊图像。不,它与逐渐应用模糊不同,但它在计算上很便宜并且是最好的解决方案。效果在工具箱中。答案 2 :(得分:3)
我很少建议现成的解决方案来解决编码问题。但是,在这种情况下,我会全心全意地推荐LiveFrost。它是一个非常可靠的UIView子类,专门用于复制流行的iOS 7高斯模糊效果。
我还鼓励您阅读作者的博客,了解他对本课程的设计决策。自从iOS 7发布以来,我已经在这个主题上做了很多研究,我对这段代码实际上是零推荐。
它甚至还有开箱即用的模糊动画!祝你好运:))
答案 3 :(得分:3)
我开发了一个小项目,使用GPUImage进行实时模糊,可变模糊半径和帧率(MSLiveBlur) - 这听起来就像你需要的那样。
在示例应用程序中,我有一个滑块可以增加/减少模糊级别以响应用户操作,正如您在问题中提到的那样。如果您想在没有用户交互的情况下为其设置动画,您可以制作一个计时器,缓慢增加模糊半径,直到达到最终值。但是,您无法在此解决方案中使用CoreAnimation。
[[MSLiveBlurView sharedInstance] setBlurInterval:0.2];
[[MSLiveBlurView sharedInstance] blurRect:someView.frame];
// Count x from 0 to your final radius
[MSLiveBlurView sharedInstance].blurRadius = x;
答案 4 :(得分:1)
这是一个可用于使用预先计算的图像为模糊设置动画的功能。你说你熟悉GPUImage所以我用它(但它也适用于简单的模糊算法)。
通过此功能,您可以在实时中为真实模糊制作动画,费用为1-2%CPU
// configuration
let imageCount: Int = 10
let blurMax: Float = 40.0
// keep images in memory
var currentIdx: Int = 0
var imgs: [UIImage] = []
// func that create the precomputed images with GPUImage (call it in the viewDidLoad for example)
func initBlur() {
let blur = GaussianBlur()
let myImage: UIImage = UIImage(named: "your_image")!
let pictureInput = PictureInput(image: myImage)
let pictureOutput = PictureOutput()
pictureOutput.onlyCaptureNextFrame = false
pictureOutput.imageAvailableCallback = { image in
self.imgs.append(image)
}
pictureInput --> blur --> pictureOutput
for i in 0...imageCount {
blur.blurRadiusInPixels = (Float(i) / Float(imageCount)) * blurMax
pictureInput.processImage(synchronously: true)
}
}
// function that return the correct image from the image set with a blur percentage from a value between 0 and 1 where 0 = no blur and 1 full blurred.
func getBlurredImage(value: Float) -> UIImage? {
// return nil if there isn't precompiled images
if imgs.count == 0 {
return nil
}
// get the desired blurred image index
let idx = Int(value * Float(imageCount - 1))
// if the index changed, check the correctness of the index
if currentIdx != idx {
if idx < 0 {
currentIdx = 0
}
else if idx >= imgs.count {
currentIdx = imageCount - 1
}
else {
currentIdx = idx
}
}
return imgs[currentIdx]
}
就是这样,接下来你可以使用它作为计时器或 scrollViewDidScroll 功能,例如:
imageView.image = getBlurredImage(value: yOffset / height)