本文翻译自:Creating a blurring overlay view
In the Music app of the new iOS, we can see an album cover behind a view that blurs it. 在新iOS的音乐应用程序中,我们可以看到一个模糊背后的专辑封面。
How can something like that be accomplished? 如何才能完成这样的事情? I've read the documentation, but did not find anything there. 我已经阅读了文档,但没有找到任何内容。
#1楼
参考:https://stackoom.com/question/19VJd/创建模糊叠加视图
#2楼
Core Image 核心形象
Since that image in the screenshot is static, you could use CIGaussianBlur
from Core Image (requires iOS 6). 由于屏幕截图中的图像是静态的,因此您可以使用Core Image中的CIGaussianBlur
(需要iOS 6)。 Here is sample: https://github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m 以下是示例: https : //github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m
Mind you, this is slower than the other options on this page. 请注意,这比此页面上的其他选项慢。
#import <QuartzCore/QuartzCore.h>
- (UIImage*) blur:(UIImage*)theImage
{
// ***********If you need re-orienting (e.g. trying to blur a photo taken from the device camera front facing camera in portrait mode)
// theImage = [self reOrientIfNeeded:theImage];
// create our blurred image
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage = [CIImage imageWithCGImage:theImage.CGImage];
// setting up Gaussian Blur (we could use one of many filters offered by Core Image)
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
// CIGaussianBlur has a tendency to shrink the image a little,
// this ensures it matches up exactly to the bounds of our original image
CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage *returnImage = [UIImage imageWithCGImage:cgImage];//create a UIImage for this function to "return" so that ARC can manage the memory of the blur... ARC can't manage CGImageRefs so we need to release it before this function "returns" and ends.
CGImageRelease(cgImage);//release CGImageRef because ARC doesn't manage this on its own.
return returnImage;
// *************** if you need scaling
// return [[self class] scaleIfNeeded:cgImage];
}
+(UIImage*) scaleIfNeeded:(CGImageRef)cgimg {
bool isRetina = [[[UIDevice currentDevice] systemVersion] intValue] >= 4 && [[UIScreen mainScreen] scale] == 2.0;
if (isRetina) {
return [UIImage imageWithCGImage:cgimg scale:2.0 orientation:UIImageOrientationUp];
} else {
return [UIImage imageWithCGImage:cgimg];
}
}
- (UIImage*) reOrientIfNeeded:(UIImage*)theImage{
if (theImage.imageOrientation != UIImageOrientationUp) {
CGAffineTransform reOrient = CGAffineTransformIdentity;
switch (theImage.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, theImage.size.height);
reOrient = CGAffineTransformRotate(reOrient, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
reOrient = CGAffineTransformRotate(reOrient, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
reOrient = CGAffineTransformTranslate(reOrient, 0, theImage.size.height);
reOrient = CGAffineTransformRotate(reOrient, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (theImage.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
reOrient = CGAffineTransformScale(reOrient, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.height, 0);
reOrient = CGAffineTransformScale(reOrient, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
CGContextRef myContext = CGBitmapContextCreate(NULL, theImage.size.width, theImage.size.height, CGImageGetBitsPerComponent(theImage.CGImage), 0, CGImageGetColorSpace(theImage.CGImage), CGImageGetBitmapInfo(theImage.CGImage));
CGContextConcatCTM(myContext, reOrient);
switch (theImage.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.height,theImage.size.width), theImage.CGImage);
break;
default:
CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.width,theImage.size.height), theImage.CGImage);
break;
}
CGImageRef CGImg = CGBitmapContextCreateImage(myContext);
theImage = [UIImage imageWithCGImage:CGImg];
CGImageRelease(CGImg);
CGContextRelease(myContext);
}
return theImage;
}
Stack blur (Box + Gaussian) 堆栈模糊(Box + Gaussian)
- StackBlur This implements a mix of Box and Gaussian blur. StackBlur这实现了Box和高斯模糊的混合。 7x faster than non accelerated gaussian, but not so ugly as box blur. 比非加速高斯快7倍,但不像盒子模糊那么难看。 See a demo in here (Java plugin version) or here (JavaScript version). 请参阅此处的演示(Java插件版本)或此处 (JavaScript版本)。 This algorithm is used in KDE and Camera+ and others. 该算法用于KDE和Camera +等。 It doesn't use the Accelerate Framework but it's fast. 它不使用Accelerate Framework,但速度很快。
Accelerate Framework 加速框架
In the session “Implementing Engaging UI on iOS” from WWDC 2013 Apple explains how to create a blurred background (at 14:30), and mentions a method
applyLightEffect
implemented in the sample code using Accelerate.framework. 在WWDC 2013的 “在iOS上实现引导UI”会议中,Apple解释了如何创建模糊背景(在14:30),并提到了使用Accelerate.framework在示例代码中实现的方法applyLightEffect
。GPUImage uses OpenGL shaders to create dynamic blurs. GPUImage使用OpenGL着色器来创建动态模糊。 It has several types of blur: GPUImageBoxBlurFilter, GPUImageFastBlurFilter, GaussianSelectiveBlur, GPUImageGaussianBlurFilter. 它有几种类型的模糊:GPUImageBoxBlurFilter,GPUImageFastBlurFilter,GaussianSelectiveBlur,GPUImageGaussianBlurFilter。 There is even a GPUImageiOSBlurFilter that “should fully replicate the blur effect provided by iOS 7's control panel” ( tweet , article ). 甚至还有一个GPUImageiOSBlurFilter“应该完全复制iOS 7控制面板提供的模糊效果”( 推文 , 文章 )。 The article is detailed and informative. 这篇文章详细而且内容丰富。
-(UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(NSInteger)blur { GPUImageFastBlurFilter *blurFilter = [GPUImageFastBlurFilter new]; blurFilter.blurSize = blur; UIImage *result = [blurFilter imageByFilteringImage:image]; return result; }
From indieambitions.com: Perform a blur using vImage . 来自indieambitions.com: 使用vImage执行模糊 。 The algorithm is also used in iOS-RealTimeBlur . 该算法也用于iOS-RealTimeBlur 。
From Nick Lockwood: https://github.com/nicklockwood/FXBlurView The example shows the blur over a scroll view. 来自Nick Lockwood: https : //github.com/nicklockwood/FXBlurView该示例显示滚动视图上的模糊。 It blurs with dispatch_async, then syncs to call updates with UITrackingRunLoopMode so the blur is not lagged when UIKit gives more priority to the scroll of the UIScrollView. 它使用dispatch_async模糊,然后同步以使用UITrackingRunLoopMode调用更新,因此当UIKit为UIScrollView的滚动提供更多优先级时,模糊不会滞后。 This is explained in Nick's book iOS Core Animation , which btw it's great. 尼克的书“ iOS核心动画”对此进行了解释,这本书很棒。
iOS-blur This takes the blurring layer of the UIToolbar and puts it elsewhere. iOS-blur这将获取UIToolbar的模糊层并将其放在其他位置。 Apple will reject your app if you use this method. 如果您使用此方法,Apple将拒绝您的应用。 See https://github.com/mochidev/MDBlurView/issues/4 请参阅https://github.com/mochidev/MDBlurView/issues/4
From Evadne blog: LiveFrost: Fast, Synchronous UIView Snapshot Convolving . 来自Evadne的博客: LiveFrost:快速,同步的UIView Snapshot Convolving 。 Great code and a great read. 伟大的代码和伟大的阅读。 Some ideas from this post: 这篇文章的一些想法:
- Use a serial queue to throttle updates from CADisplayLink. 使用串行队列限制CADisplayLink的更新。
- Reuse bitmap contexts unless bounds change. 除非边界发生变化,否则重用位图上下文。
- Draw smaller images using -[CALayer renderInContext:] with a 0.5f scale factor. 使用 - [CALayer renderInContext:]以0.5f比例因子绘制较小的图像。
Other stuff 其他的东西
Andy Matuschak said on Twitter: “you know, a lot of the places where it looks like we're doing it in real time, it's static with clever tricks.” Andy Matuschak在推特上说 :“你知道,很多地方看起来我们都是在实时做这件事,但这很聪明,技巧娴熟。”
At doubleencore.com they say “we've found that a 10 pt blur radius plus a 10 pt increase in saturation best mimics iOS 7's blur effect under most circumstances”. 在doubleencore.com,他们说“我们发现在大多数情况下,10点的模糊半径加上10点的饱和度增加最能模仿iOS 7的模糊效果”。
A peek at the private headers of Apple's SBFProceduralWallpaperView . 看看Apple的SBFProceduralWallpaperView的私人标题。
Finally, this isn't a real blur, but remember you can set rasterizationScale to get a pixelated image: http://www.dimzzy.com/blog/2010/11/blur-effect-for-uiview/ 最后,这不是真正的模糊,但请记住,您可以设置rasterizationScale来获取像素化图像: http : //www.dimzzy.com/blog/2010/11/blur-effect-for-uiview/
#3楼
I don't think I'm allowed to post the code, but the above post mentioning the WWDC sample code is correct. 我不认为我可以发布代码,但上面提到WWDC示例代码的帖子是正确的。 Here is the link: https://developer.apple.com/downloads/index.action?name=WWDC%202013 这是链接: https : //developer.apple.com/downloads/index.action?name = WWDC%202020
The file you're looking for is the category on UIImage, and the method is applyLightEffect. 您要查找的文件是UIImage上的类别,方法是applyLightEffect。
As I noted above in a comment, the Apple Blur has saturation and other things going on besides blur. 正如我在评论中所提到的,Apple Blur除了模糊之外还有饱和度和其他事情。 A simple blur will not do... if you are looking to emulate their style. 一个简单的模糊不会...如果你想模仿他们的风格。
#4楼
Found this by accident, gives me really great (near duplicate with Apple's) results and uses the Acceleration framework. 偶然发现这个,给了我非常好的(与Apple的重复)结果,并使用Acceleration框架。 -- http://pastebin.com/6cs6hsyQ *Not written by me - http://pastebin.com/6cs6hsyQ *不是我写的
#5楼
I think the easiest solution to this is to override UIToolbar, which blurs everything behind it in iOS 7. It's quite sneaky, but it's very simple for you to implement, and fast! 我认为最简单的解决方案是覆盖UIToolbar,它在iOS 7中模糊了它背后的一切。它非常狡猾,但它实现起来非常简单,而且速度快!
You can do it with any view, just make it a subclass of UIToolbar
instead of UIView
. 您可以使用任何视图执行此操作,只需将其UIToolbar
的子类而不是UIView
。 You can even do it with a UIViewController
's view
property, for example... 您甚至可以使用UIViewController
的view
属性来执行此操作,例如...
1) create a new class that is a "Subclass of" UIViewController
and check the box for "With XIB for user interface". 1)创建一个新类,它是UIViewController
的“子类”,并选中“With XIB for user interface”框。
2) Select the View and go to the identity inspector in the right-hand panel (alt-command-3). 2)选择View并转到右侧面板中的身份检查器(alt-command-3)。 Change the "Class" to UIToolbar
. 将“Class”更改为UIToolbar
。 Now go to the attributes inspector (alt-command-4) and change the "Background" color to "Clear Color". 现在转到属性检查器(alt-command-4)并将“背景”颜色更改为“清除颜色”。
3) Add a subview to the main view and hook it up to an IBOutlet in your interface. 3)将子视图添加到主视图并将其连接到界面中的IBOutlet。 Call it backgroundColorView
. 称之为backgroundColorView
。 It will look something like this, as a private category in the implementation ( .m
) file. 它看起来像这样,作为实现( .m
)文件中的私有类。
@interface BlurExampleViewController ()
@property (weak, nonatomic) IBOutlet UIView *backgroundColorView;
@end
4) Go to the view controller implementation ( .m
) file and change the -viewDidLoad
method, to look as follows: 4)转到视图控制器实现( .m
)文件并更改-viewDidLoad
方法,如下所示:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.barStyle = UIBarStyleBlack; // this will give a black blur as in the original post
self.backgroundColorView.opaque = NO;
self.backgroundColorView.alpha = 0.5;
self.backgroundColorView.backgroundColor = [UIColor colorWithWhite:0.3 alpha:1];
}
This will give you a dark gray view, which blurs everything behind it. 这会给你一个深灰色的视图,模糊背后的一切。 No funny business, no slow core image blurring, using everything that is at your fingertips provided by the OS/SDK. 没有有趣的业务,没有缓慢的核心图像模糊,使用OS / SDK提供的触手可及的一切。
You can add this view controller's view to another view, as follows: 您可以将此视图控制器的视图添加到另一个视图,如下所示:
[self addChildViewController:self.blurViewController];
[self.view addSubview:self.blurViewController.view];
[self.blurViewController didMoveToParentViewController:self];
// animate the self.blurViewController into view
Let me know if anything is unclear, I'll be happy to help! 如果有什么不清楚,请告诉我,我很乐意提供帮助!
Edit 编辑
UIToolbar has been changed in 7.0.3 to give possibly-undesirable effect when using a coloured blur. UIToolbar在7.0.3中已更改,在使用彩色模糊时可能会产生不良影响。
We used to be able to set the colour using barTintColor
, but if you were doing this before, you will need to set the alpha component to less than 1. Otherwise your UIToolbar will be completely opaque colour - with no blur. 我们曾经能够使用barTintColor
设置颜色,但如果您之前这样做,则需要将alpha组件设置为小于1.否则您的UIToolbar将是完全不透明的颜色 - 没有模糊。
This can be achieved as follows: (bearing in mind self
is a subclass of UIToolbar
) 这可以通过以下方式实现:(记住self
是UIToolbar
的子类)
UIColor *color = [UIColor blueColor]; // for example
self.barTintColor = [color colorWithAlphaComponent:0.5];
This will give a blue-ish tint to the blurred view. 这将为模糊的视图提供蓝色色调。
#6楼
You can use UIVisualEffectView
to achieve this effect. 您可以使用UIVisualEffectView
来实现此效果。 This is a native API that has been fine-tuned for performance and great battery life, plus it's easy to implement. 这是一个本机API,经过微调,性能和电池寿命长,而且易于实现。
Swift: 迅速:
//only apply the blur if the user hasn't disabled transparency effects
if !UIAccessibility.isReduceTransparencyEnabled {
view.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
view.backgroundColor = .black
}
Objective-C: Objective-C的:
//only apply the blur if the user hasn't disabled transparency effects
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
self.view.backgroundColor = [UIColor clearColor];
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
//always fill the view
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:blurEffectView]; //if you have more UIViews, use an insertSubview API to place it where needed
} else {
self.view.backgroundColor = [UIColor blackColor];
}
If you are presenting this view controller modally to blur the underlying content, you'll need to set the modal presentation style to Over Current Context and set the background color to clear to ensure the underlying view controller will remain visible once this is presented overtop. 如果您以模态方式呈现此视图控制器以模糊基础内容,则需要将模式演示文稿样式设置为“当前上下文”并将背景颜色设置为“清除”以确保基础视图控制器在显示为超出时保持可见。