ios 创建模糊叠加视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17041669/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:53:37  来源:igfitidea点击:

Creating a blurring overlay view

iosobjective-cgraphicsfilteringcore-image

提问by kondratyevdev

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.

怎么可能完成这样的事情?我已经阅读了文档,但在那里没有找到任何东西。

回答by Jordan H

You can use UIVisualEffectViewto achieve this effect. This is a native API that has been fine-tuned for performance and great battery life, plus it's easy to implement.

你可以用它UIVisualEffectView来达到这个效果。这是一个原生 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:

目标-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.

如果您以模态方式呈现此视图控制器以模糊底层内容,则需要将模态呈现样式设置为 Over Current Context 并将背景颜色设置为 clear 以确保底层视图控制器在将其呈现在顶部时保持可见。

回答by Jano

Core Image

核心形象

Since that image in the screenshot is static, you could use CIGaussianBlurfrom Core Image (requires iOS 6). Here is sample: https://github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m

由于屏幕截图中的图像是静态的,您可以使用CIGaussianBlurCore Image(需要 iOS 6)。这是示例: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)

堆栈模糊(框 + 高斯)

  • StackBlurThis implements a mix of Box and Gaussian blur. 7x faster than non accelerated gaussian, but not so ugly as box blur. See a demo in here(Java plugin version) or here(JavaScript version). This algorithm is used in KDE and Camera+ and others. It doesn't use the Accelerate Framework but it's fast.
  • StackBlur这实现了 Box 和 Gaussian 模糊的混合。比非加速高斯快 7 倍,但不像框模糊那么难看。在此处(Java 插件版本)或此处(JavaScript 版本)查看演示。该算法用于 KDE 和 Camera+ 等。它不使用加速框架,但速度很快。

Accelerate Framework

加速框架

  • In the session “Implementing Engaging UI on iOS” from WWDC 2013Apple explains how to create a blurred background (at 14:30), and mentions a method applyLightEffectimplemented in the sample code using Accelerate.framework.

  • GPUImageuses OpenGL shaders to create dynamic blurs. It has several types of blur: 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). The article is detailed and informative.

  • WWDC 2013 的“在 iOS 上实现引人入胜的 UI”会议中,Apple 解释了如何创建模糊背景(14:30),并提到了applyLightEffect使用 Accelerate.framework 在示例代码中实现的方法。

  • GPUImage使用 OpenGL 着色器来创建动态模糊。它有几种类型的模糊:GPUImageBoxBlurFilter、GPUImageFastBlurFilter、GaussianSelectiveBlur、GPUImageGaussianBlurFilter。甚至还有一个 GPUImageiOSBlurFilter,“应该完全复制 iOS 7 控制面板提供的模糊效果”(推文文章)。这篇文章详细而翔实。

    -(UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(NSInteger)blur {
        GPUImageFastBlurFilter *blurFilter = [GPUImageFastBlurFilter new];
        blurFilter.blurSize = blur;
        UIImage *result = [blurFilter imageByFilteringImage:image];
        return result;
    }

Other stuff

其他的东西

Andy Matuschak saidon 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.comthey 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 pt 的模糊半径加上 10 pt 的饱和度增加在大多数情况下最能模仿 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/

回答by valbu17

I decided to post a written Objective-C version from the accepted answer just to provide more options in this question..

我决定从接受的答案中发布一个书面的 Objective-C 版本,只是为了在这个问题中提供更多选项。

- (UIView *)applyBlurToView:(UIView *)view withEffectStyle:(UIBlurEffectStyle)style andConstraints:(BOOL)addConstraints
{
  //only apply the blur if the user hasn't disabled transparency effects
  if(!UIAccessibilityIsReduceTransparencyEnabled())
  {
    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    blurEffectView.frame = view.bounds;

    [view addSubview:blurEffectView];

    if(addConstraints)
    {
      //add auto layout constraints so that the blur fills the screen upon rotating device
      [blurEffectView setTranslatesAutoresizingMaskIntoConstraints:NO];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeTop
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeTop
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeBottom
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeBottom
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeLeading
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeLeading
                                                      multiplier:1
                                                        constant:0]];

      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView
                                                       attribute:NSLayoutAttributeTrailing
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:view
                                                       attribute:NSLayoutAttributeTrailing
                                                      multiplier:1
                                                        constant:0]];
    }
  }
  else
  {
    view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
  }

  return view;
}

The constraints could be removed if you want incase if you only support portrait mode or I just add a flag to this function to use them or not..

如果您只支持纵向模式,或者我只是在此函数中添加一个标志以使用它们,则可以删除这些约束。

回答by xtravar

I don't think I'm allowed to post the code, but the above post mentioning the WWDC sample code is correct. Here is the link: https://developer.apple.com/downloads/index.action?name=WWDC%202013

我不认为我被允许发布代码,但上面提到 WWDC 示例代码的帖子是正确的。这是链接:https: //developer.apple.com/downloads/index.action?name=WWDC%202013

The file you're looking for is the category on UIImage, and the method is applyLightEffect.

你要找的文件是UIImage上的category,方法是applyLightEffect。

As I noted above in a comment, the Apple Blur has saturation and other things going on besides blur. A simple blur will not do... if you are looking to emulate their style.

正如我在上面的评论中指出的那样,Apple Blur 具有饱和度和除模糊之外的其他功能。一个简单的模糊不会做...如果你想模仿他们的风格。

回答by kev

Here's a fast implementation in Swift using CIGaussianBlur:

这是使用 CIGaussianBlur 在 Swift 中的快速实现:

func blur(image image: UIImage) -> UIImage {
    let radius: CGFloat = 20;
    let context = CIContext(options: nil);
    let inputImage = CIImage(CGImage: image.CGImage!);
    let filter = CIFilter(name: "CIGaussianBlur");
    filter?.setValue(inputImage, forKey: kCIInputImageKey);
    filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);
    let result = filter?.valueForKey(kCIOutputImageKey) as! CIImage;
    let rect = CGRectMake(radius * 2, radius * 2, image.size.width - radius * 4, image.size.height - radius * 4)
    let cgImage = context.createCGImage(result, fromRect: rect);
    let returnImage = UIImage(CGImage: cgImage);

    return returnImage;
}

回答by Sam

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 UIToolbarinstead of UIView. You can even do it with a UIViewController's viewproperty, for example...

您可以使用任何视图执行此操作,只需将其设为 的子类UIToolbar而不是UIView. 你甚至可以用 aUIViewControllerview属性来做,例如......

1) create a new class that is a "Subclass of" UIViewControllerand check the box for "With XIB for user interface".

1)创建一个新类,它是“子类”UIViewController并选中“使用 XIB 用于用户界面”框。

2) Select the View and go to the identity inspector in the right-hand panel (alt-command-3). Change the "Class" to UIToolbar. Now go to the attributes inspector (alt-command-4) and change the "Background" color to "Clear Color".

2) 选择视图并转到右侧面板中的身份检查器 (alt-command-3)。将“类”更改为UIToolbar. 现在转到属性检查器(alt-command-4)并将“背景”颜色更改为“清除颜色”。

3) Add a subview to the main view and hook it up to an IBOutlet in your interface. Call it backgroundColorView. It will look something like this, as a private category in the implementation (.m) file.

3) 将子视图添加到主视图并将其连接到界面中的 IBOutlet。叫它backgroundColorView。它看起来像这样,作为实现 ( .m) 文件中的私有类别。

@interface BlurExampleViewController ()
@property (weak, nonatomic) IBOutlet UIView *backgroundColorView;
@end

4) Go to the view controller implementation (.m) file and change the -viewDidLoadmethod, 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 selfis 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.

这将为模糊的视图提供蓝色调。

回答by Adam Bardon

Here's an easy way to add custom blur without haggling with private APIs using UIViewPropertyAnimator:

这是使用UIViewPropertyAnimator添加自定义模糊而不与私有 API 讨价还价的简单方法:

First, declare class property:

首先,声明类属性:

var blurAnimator: UIViewPropertyAnimator!

Then set your blur view in viewDidLoad():

然后将您的模糊视图设置为viewDidLoad()

let blurEffectView = UIVisualEffectView()
blurEffectView.backgroundColor = .clear
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView)

blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [blurEffectView] in
    blurEffectView.effect = UIBlurEffect(style: .light)
}

blurAnimator.fractionComplete = 0.15 // set the blur intensity.    

Note:This solution is not suitable for UICollectionView/UITableViewcells

注意:此解决方案不适用于UICollectionView/UITableView单元格

回答by Hyman

Custom blur scale

自定义模糊比例

You can tryUIVisualEffectViewwith custom setting as -

您可以尝试UIVisualEffectView使用自定义设置作为 -

class BlurViewController: UIViewController {
    private let blurEffect = (NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type).init()

    override func viewDidLoad() {
        super.viewDidLoad()
        let blurView = UIVisualEffectView(frame: UIScreen.main.bounds)
        blurEffect.setValue(1, forKeyPath: "blurRadius")
        blurView.effect = blurEffect
        view.addSubview(blurView)
    }   
}

Output:- for blurEffect.setValue(1...& blurEffect.setValue(2..enter image description hereenter image description here

输出:- 对于 blurEffect.setValue(1...& blurEffect.setValue(2..在此处输入图片说明在此处输入图片说明

回答by Mehedi Hasan

enter image description here

在此处输入图片说明

From Xcode you can do it easily. Follow the steps from xcode. Drage visual effect view on your uiview or imageview.

从 Xcode 您可以轻松完成。按照 xcode 中的步骤操作。在 uiview 或 imageview 上拖动视觉效果视图。

Happy Coding :)

快乐编码:)

回答by Aleksandar Vaci?

Accepted answer is correct but there's an important step missing here, in case this view - for which you want blurred background - is presented using

接受的答案是正确的,但这里缺少一个重要的步骤,以防此视图 - 您想要模糊背景 - 使用

[self presentViewController:vc animated:YES completion:nil]

[self presentViewController:vc animated:YES completion:nil]

By default, this will negate the blur as UIKit removes the presenter's view, which you are actually blurring. To avoid that removal, add this line before the previous one

默认情况下,这将消除模糊,因为 UIKit 删除了演示者的视图,您实际上正在模糊它。为避免删除,请在上一行之前添加此行

vc.modalPresentationStyle = UIModalPresentationOverFullScreen;

vc.modalPresentationStyle = UIModalPresentationOverFullScreen;

Or use other Overstyles.

或者使用其他Over样式。