iOS 7 风格的模糊视图

Posted

技术标签:

【中文标题】iOS 7 风格的模糊视图【英文标题】:iOS 7 style Blur view 【发布时间】:2013-06-06 20:42:28 【问题描述】:

有没有人知道任何可以复制 ios7 风格模糊视图的控件。

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

我说的是这些类型的视图,它们非常模糊背景,因此它们具有来自背景视图的拉动效果。

【问题讨论】:

GPUImage 可能会有所帮助。 @Anil 那么问题将是 ios7 SDK 何时发布,如何在不将我的应用程序仅限于 ios7 的情况下做到这一点;)。 iOS7 get wallpaper / cover image and create blurred view的可能重复 Apple 已经发布了一个 UIImage 类别来实现这一点。只是想找到它。 代码链接自 WWDC session 201。它在 github 上是公开的,我只是在 atm 上找不到。 【参考方案1】:

您也许可以修改像 Bin Zhang 的 RWBlurPopover 这样的东西来做到这一点。该组件使用我的 GPUImage 对其下方的组件应用高斯模糊,但您也可以轻松地使用 CIGaussianBlur。 GPUImage 可能是a hair faster though。

但是,该组件依赖于您能够捕获您正在呈现的组件背后的视图,并且可能无法处理在该内容背后进行动画处理的视图。需要通过 Core Graphics 来光栅化背景视图会减慢速度,因此我们可能没有足够的直接访问权限,无法以高性能的方式在动画视图上执行此操作。

作为对上述内容的更新,我最近重新设计了 GPUImage 中的模糊以支持可变半径,从而允许在 iOS 7 的控制中心视图中完全复制模糊大小。由此,我创建了 GPUImageiOS7BlurFilter 类,它封装了 Apple 似乎在这里使用的正确模糊大小和颜色校正。这是 GPUImage 的模糊(右侧)与内置模糊(左侧)的比较:

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

您仍然面临着如何以高效的方式将内容从该视图后面的视图中提取到这种模糊中的挑战。

【讨论】:

那么您认为 Apple 是如何成功的?如果您打开相机应用程序,然后拉起控制中心(底部的设置屏幕),模糊会跟随相机看到的内容。 @maq - 它有助于在后台访问系统上的所有内容。开发操作系统的人可以做的与公共接口让我们做的非常不同。 @maq - 专门用于摄像头,是的。一种方法是使用 GPUImage 拉入相机帧(通过 AV Foundation),然后将其输出到 GPUImageView 以进行实时相机输出,然后并行输入高斯模糊(可能还有裁剪)以匹配模糊视图的位置)并将该输出输出到另一个 GPUImageView,该 GPUImageView 将在您的控件后面显示模糊内容。这是可能的,因为我们有从相机帧到 OpenGL ES 的快速路径,但对于通用 UI 元素,我们没有任何类似的东西。 我正在以编程方式截取 UIView 的屏幕截图并使用 GPUImageGaussianBlurFilter 尝试创建类似的效果,但结果与 Apple 风格的效果非常不同。过滤器似乎在网格中变得模糊,到处都是可见的正方形,而 Apple 的只是一张光滑的纸。 @maq - 确保您使用的是存储库中的最新代码,因为之前存在高模糊半径的错误。也就是说,默认情况下,模糊仅对 9 像素区域进行采样,因此如果您将模糊的乘数增加超过该点,您将开始看到跳过像素的伪影。这样做是出于性能原因,但您可以修改顶点和片段着色器以采样更多像素。或者尝试应用 CIGaussianBlur,它具有更通用的模糊实现。有一天,我会将这种模糊扩展到更大的半径。【参考方案2】:

我正在使用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];

【讨论】:

使用 FXBlurView 有什么技巧吗?我已经尝试过了,但是我们在 iPhone 5 上导致了延迟视图。他们的演示项目运行良好。相当奇怪。 这取决于你想做什么。当我将FXBlurView 放在UIScrollView 上时,我也得到了一个滞后的结果。我相信这与添加模糊的方式有关。如果我没记错的话,Apple 会在使用自己的模糊时直接访问 GPU,而我们作为开发人员无法做到这一点。因此,@cprcrack 解决方案实际上是这里最好的解决方案。 您是如何使用 FXBlurView 处理设备旋转的?我现在正在展示一个模态对话框;对话框本身可以很好地旋转,但背景被错误地挤压(基本上需要在旋转后更新)。 当然,FXBlurView 是不错的选择,但是当涉及到 CPU 使用率时。比我更喜欢其他模糊视图。我在我的 UICollectionVIew 和 UITableView 中使用它,但它增加了我的 CPU 使用率。在下一次运行中,我评论了这些分配,它变得正常了。我希望,这会对某人有所帮助。【参考方案3】:

警告:cmets 中有人表示 Apple 拒绝使用这种技术的应用程序。这没有发生在我身上,只是为了你的考虑。

这可能会让您大吃一惊,但您可以使用 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

【讨论】:

是的,这让我很惊讶。我验证了,这个想法确实有效。我像这样在viewDidLoad 中只更改了一行。 - (void)viewDidLoad [超级 viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame:CGRectZero];就我而言,我以编程方式(旧式)布局我的视图。我赞成这个解决方案,因为 UIToolbar 继承了 UIView 所以从根本上我没有看到这个解决方案有任何问题。随着开发和测试此解决方案的进行,我将进行更多测试。 这是个好主意,而且看起来效果很好。希望我有更多的控制权,但这已经很好了!也就是说,@SudhirJonathan 提到了上面的链接,作者将其提升到了一个新的水平 - 他从 UIToolBar 窃取了 CALAYER 并重新使用它!太棒了! 真的吗?有哪些依据?它没有使用任何私有 API,如果所有创新的做事方式都被拒绝,那么很多效果都是不可能的...... 在我的 iOS 7.1 iPhone 上工作 有没有办法让模糊“消失”?【参考方案4】:

您可以使用作为 UIView 子类的 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 这是向另一个视图控制器添加透明视图的更有效方法之一。我包含了 AVCapture 代码,以表明它可以用于实时反馈,而不是像其他用户推荐的那样仅仅添加模糊的背景图像。 好的,抱歉,您可能想在开头添加一些东西,总结一下方法和使用它的原因。 @combinatorial 谢谢【参考方案5】:

iOS8 起可以使用UIBlurEffect。

iOS8Sampler 上有一个很好的例子,UIBlurEffect 和 UIVibrancyEffect。

【讨论】:

懒人:UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];【参考方案6】:

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

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

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

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect 支持三种样式。深色、浅色和超浅色。

【讨论】:

以上是关于iOS 7 风格的模糊视图的主要内容,如果未能解决你的问题,请参考以下文章

iOS 6 应用程序在 iOS 7 风格上运行

如何构建 iOS7 风格的录音机应用程序

复制 iOS Mail App 的 Compose Function 的风格

我应该如何在 iOS 7 中使用具有 iOS 6 风格的 UIButtons?

实现 iOS Maps 风格的页面卷曲手势交互

从左滑动返回之前风格的 iOS 屏幕 Flutter