iOS 7 风格的模糊视图

113

有人知道任何可以复制iOS7风格模糊视图的控件吗?

我假设可能会有某种UIView子类可以复制这个行为。

我指的是那些非常浓厚地模糊背景的视图,以便它们从背景视图中产生拉动效果。

输入图片描述


6
可能会有帮助的是GPUImage - Maarten
1
苹果公司发布了一个UIImage类别,可以完美地实现这一点。我只是在尝试找到它。 - Fogmeister
1
代码链接来自于WWDC 201会议。它在Github上是公开的,但我目前找不到它。 - Fogmeister
在Xcode中实现iOS7风格的模糊效果:http://www.youtube.com/watch?feature=player_embedded&v=JIdcYbAd-NI - Aleksandr Sis'ov
如果你只对iOS7+上带有GPU支持和实时动画的模糊效果感兴趣,请尝试这个链接: https://dev59.com/QGQn5IYBdhLWcg3wJ0YO#19506076 - Ivo Leko
显示剩余8条评论
6个回答

40
您可以尝试修改类似于Bin Zhang的RWBlurPopover来实现。该组件使用我的GPUImage将高斯模糊应用于其下方的组件,但您也可以同样轻松地使用CIGaussianBlur。然而,GPUImage可能会稍微快一些

但是,该组件依赖于您能够捕获在您要显示的视图之后的视图,并且对于在此内容后面动画的视图可能会出现问题。需要通过核心绘图来光栅化背景视图,这将减慢速度,因此我们可能没有足够直接的访问权限以便能够以性能良好的方式执行覆盖层和动画视图之间的高斯模糊。

最近,我更新了GPUImage中的模糊功能以支持可变半径,从而允许完全复制iOS 7控制中心视图中的模糊大小。由此,我创建了GPUImageiOS7BlurFilter类,该类封装了正确的模糊大小和颜色校正,苹果似乎正在此处使用。这是GPUImage的模糊(在右侧)与内置模糊(在左侧)的比较:

苹果的模糊 GPUImage的模糊

我使用4倍下采样/上采样来减少高斯模糊操作的像素数量,因此iPhone 4S可以在大约30毫秒内模糊整个屏幕。

仍然有一个挑战,即如何以性能良好的方式将内容从该视图后面的视图中插入到此模糊效果中。


2
@maq - 拥有对系统中所有内容的底层访问权限确实很有帮助。开发操作系统的人所能做的与公共接口所允许我们做的非常不同。 - Brad Larson
3
@maq - 是的,具体来说是摄像头的视频输入。一种实现方法是使用GPUImage通过AV Foundation获取摄像头帧,并将其输出到一个GPUImageView用于实时摄像头输出,同时并行地被馈送到高斯模糊(可能还要进行裁剪以匹配模糊视图的位置),并且该输出将显示在另一个GPUImageView中,在您的控件后面显示模糊内容。这是可能的,因为我们有从摄像头帧到OpenGL ES的快速路径,但对于通用UI元素,我们没有类似的东西。 - Brad Larson
1
我正在通过编程方式对UIView进行屏幕截图,并使用GPUImageGaussianBlurFilter尝试创建类似的效果,但结果与苹果风格的效果非常不同。该滤镜似乎在网格中模糊,到处可见方形,而苹果的则是一个平滑的表面。 - Snowman
1
@maq - 确保您正在使用存储库中的最新代码,因为以前在高模糊半径下存在错误。话虽如此,默认情况下,模糊只对9像素区域进行采样,因此如果您将模糊的乘数增加到该点之上,则会开始看到跳过像素的伪影。出于性能原因,这样做,但是您可以修改顶点和片段着色器以采样更多的像素。或者尝试应用CIGaussianBlur,它具有更广义的模糊实现。总有一天,我会将此模糊扩展到更大的半径。 - Brad Larson
@bendytree,与对整个图像进行模糊处理相比,结果效果有何不同?您获得了多少性能提升? - fengd
显示剩余4条评论

28

我正在使用 FXBlurView,它在iOS5及以上版本上运行良好。

https://github.com/nicklockwood/FXBlurView

CocoaPods:

-> FXBlurView (1.3.1)
   UIView subclass that replicates the iOS 7 realtime background blur effect, but works on iOS 5 and above.
   pod 'FXBlurView', '~> 1.3.1'
   - Homepage: http://github.com/nicklockwood/FXBlurView
   - Source:   https://github.com/nicklockwood/FXBlurView.git
   - Versions: 1.3.1, 1.3, 1.2, 1.1, 1.0 [master repo]
我使用以下方式添加它:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];

2
使用FXBlurView有什么技巧吗?我已经尝试过了,但在iPhone 5上会导致视图卡顿。他们的演示项目运行良好。相当奇怪。 - Cris
这取决于你想做什么。当我将FXBlurView放在UIScrollView的顶部时,我也得到了一个卡顿的结果。我认为这与添加模糊的方式有关。如果我没有记错,苹果在使用自己的模糊时直接访问GPU,而作为开发人员我们无法这样做。因此,@cprcrack的解决方案实际上是最好的解决方案。 - Paul Peelen
2
你是如何处理FXBlurView的设备旋转?我目前正在展示一个模态对话框;对话框本身可以很好地旋转,但背景却被挤压到了错误的方向(基本上需要在旋转后更新它)。 - fatuhoku
1
当然,FXBlurView是一个不错的选择,但当涉及到CPU使用时,我更喜欢其他的blurView。我在我的UICollectionVIew和UITableView中使用它,但它增加了我的CPU使用率。在下一次运行中,我注释掉这些分配,它就恢复正常了。我希望这能帮助到某些人。 - Vatsal Shukla

27

警告:评论中有人表示苹果会拒绝使用此技术的应用。我没有遇到过这种情况,但请您考虑一下。

这可能会让你惊讶,但你可以使用一个UIToolbar,它已经包含了这个标准效果(仅限iOS 7+)。在你的视图控制器的viewDidLoad方法中:

self.view.opaque = NO;
self.view.backgroundColor = [UIColor clearColor]; // Be sure in fact that EVERY background in your view's hierarchy is totally or at least partially transparent for a kind effect!

UIToolbar *fakeToolbar = [[UIToolbar alloc] initWithFrame:self.view.bounds];
fakeToolbar.autoresizingMask = self.view.autoresizingMask;
// fakeToolbar.barTintColor = [UIColor white]; // Customize base color to a non-standard one if you wish
[self.view insertSubview:fakeToolbar atIndex:0]; // Place it below everything

1
是的,这让我很惊讶。我验证了一下,这个想法确实可行。我只在 viewDidLoad 中做了一行更改,像这样:- (void)viewDidLoad { [super viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame:CGRectZero]; } 在我的情况下,我以编程方式布局我的视图(旧风格)。我赞成这个解决方案,因为 UIToolbar 继承自 UIView,所以从根本上讲,我不认为这个解决方案有任何问题。随着开发的进行,我会进行更多测试并测试这个解决方案。 - Ashok
这是一个很棒的想法,看起来运行得非常好。希望我能有更多的控制,但这已经是最好的了!话虽如此,@SudhirJonathan在上面提到了一个链接,作者将其提升到了下一个级别 - 他从UIToolBar中窃取了CALayer并重新利用它!太棒了! - David H
2
真的吗?根据什么?它没有使用任何私有API,如果所有创新的方法都被拒绝,很多效果将不可能实现... - TheEye
在我的iOS 7.1 iPhone上工作过。 - marsant
有没有办法“减轻”模糊程度? - maxisme

13

使用新的 iOS 8 功能 UIVisualEffectView 是获得模糊叠加效果的最佳新方法。

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

UIVisualEffectView *bluredView = [[UIVisualEffectView alloc] initWithEffect:effect];

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect支持三种样式:Dark,Light和ExtraLight。


13

2
懒人专用: `UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];` - Ric Santos

1
你可以创建一个UIToolBar的子类,并将其实例化到一个单独的视图控制器中。这种方法展示了一个半透明的UIToolBar(由UIView子类化),提供实时反馈(在这种情况下用于AVCaptureSession)。

YourUIView.h

#import <UIKit/UIKit.h>

@interface YourUIView : UIView
@property (nonatomic, strong) UIColor *blurTintColor;
@property (nonatomic, strong) UIToolbar *toolbar;
@end

YourUIView.m

#import "YourUIView.h"

@implementation YourUIView

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    // If we don't clip to bounds the toolbar draws a thin shadow on top
    [self setClipsToBounds:YES];

    if (![self toolbar]) {
        [self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
        [self.toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self insertSubview:[self toolbar] atIndex:0];

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
    }
}

- (void) setBlurTintColor:(UIColor *)blurTintColor {
    [self.toolbar setBarTintColor:blurTintColor];
}

@end

一旦上述UIView被定制,继续创建一个继承自ViewController的子类。下面我创建了一个使用AVCapture会话的类。必须使用AVCaptureSession来覆盖苹果内置相机配置。因此,您可以在YourUIView类中叠加半透明的UIToolBar。

YourViewController.h

#import <UIKit/UIKit.h>

@interface YourViewController : UIViewController
@property (strong, nonatomic) UIView *frameForCapture;
@end

YourViewController.m

#import "YourViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "TestView.h"

@interface YourViewController ()
@property (strong, nonatomic) UIButton *displayToolBar;

@end

@implementation YourViewController


AVCaptureStillImageOutput *stillImageOutput;
AVCaptureSession *session;

- (void) viewWillAppear:(BOOL)animated
{
    session = [[AVCaptureSession alloc] init];
    [session setSessionPreset:AVCaptureSessionPresetPhoto];

    AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];

    if ([session canAddInput:deviceInput]) {
        [session addInput:deviceInput];
    }

    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    CGRect frame = [[UIScreen mainScreen] bounds];

    self.frameForCapture.frame = frame;

    [previewLayer setFrame:frame];

    [rootLayer insertSublayer:previewLayer atIndex:0];

    stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];

    [session addOutput:stillImageOutput];

    [session startRunning];

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}


- (void)viewDidLoad
{
    [super viewDidLoad];

    /* Open button */

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 350, self.view.bounds.size.width, 50)];
    [button addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Open" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    button.backgroundColor = [UIColor greenColor];
    [self.view addSubview:button];

    UIButton *anotherButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, 50)];
    [anotherButton addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [anotherButton setTitle:@"Open" forState:UIControlStateNormal];
    [anotherButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
    anotherButton.backgroundColor = [UIColor redColor];
    [self.view addSubview:anotherButton];

}

- (void) showYourUIView:(id) sender
{
    TestView *blurView = [TestView new];
    [blurView setFrame:self.view.bounds];
    [self.view addSubview:blurView];
}


@end

答案似乎与问题完全无关。 - combinatorial
@combinatorial 这是一种更有效的方法,将透明视图添加到另一个视图控制器中。我包含了AVCapture代码,以展示它可以用于实时反馈,而不仅仅是添加模糊的背景图片,正如其他用户所推荐的那样。 - 74U n3U7r1no
好的,抱歉,您可能需要在开头添加一些概括方法和使用它的原因的内容。 - combinatorial
@combinatorial 谢谢 - 74U n3U7r1no

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接