iOS 7半透明模态视图控制器

77
iOS 7 上的 App Store 应用程序使用了一种模糊玻璃效果,可以看到背后的视图。这是使用 iOS 7 内置的 API 还是自定义代码实现的?我希望是前者,但我在文档中没有找到任何明显的参考。明显的事情(如在模态视图上设置 alpha 属性)似乎没有任何效果。
要查看示例,请打开 App Store 应用并按右上角的按钮。 App Store home page Modal view in the App Store

我喜欢你的问题。 - Tà Truhoada
13个回答

132

iOS 8.0发布后,不再需要获取图像并对其进行模糊处理。正如Andrew Plummer所指出的那样,您可以使用UIVisualEffectViewUIBlurEffect

UIViewController * contributeViewController = [[UIViewController alloc] init];
UIBlurEffect * blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *beView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
beView.frame = self.view.bounds;

contributeViewController.view.frame = self.view.bounds;
contributeViewController.view.backgroundColor = [UIColor clearColor];
[contributeViewController.view insertSubview:beView atIndex:0];
contributeViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

[self presentViewController:contributeViewController animated:YES completion:nil];

在 iOS 8 之前有效的解决方案

我想在 rckoenes 的答案上进行拓展:

正如强调的那样,您可以通过以下方式创建这种效果:

  1. 将底层 UIView 转换为 UIImage
  2. 模糊 UIImage
  3. 将 UIImage 设置为视图的背景。

enter image description here


听起来很麻烦,但实际上非常简单:

1. 创建一个 UIView 类别并添加以下方法:

-(UIImage *)convertViewToImage
{
    UIGraphicsBeginImageContext(self.bounds.size);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

2. 使用苹果的图像效果类别 (下载) 对当前视图进行截图并模糊处理

UIImage* imageOfUnderlyingView = [self.view convertViewToImage];
imageOfUnderlyingView = [imageOfUnderlyingView applyBlurWithRadius:20
                             tintColor:[UIColor colorWithWhite:1.0 alpha:0.2]
                 saturationDeltaFactor:1.3
                             maskImage:nil];

3. 将其设置为覆盖层的背景。

-(void)viewDidLoad
{
   self.view.backgroundColor = [UIColor clearColor];
   UIImageView* backView = [[UIImageView alloc] initWithFrame:self.view.frame];
   backView.image = imageOfUnderlyingView;
   backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
   [self.view addSubview:backView];
}

2
https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip - 图像效果类别的直接链接 - OneManBand
@OneManBand 已添加了链接。谢谢! - Sebastian Hojas
3
这不会像应用商店的模态视图控制器一样行为,它实际上会动态模糊底部内容 - 包括动画特色应用。 - Vadoff
2
自iOS 8以来,终于有了一种直接的方法来通过UIModalPresentationOverCurrentContext实现此效果。请参见下面Andrew Plummer,mxcl和Andrey Konstantinov的答案。 - Renfei Song
这个不会保持模糊状态吗?使用iOS 8的方法,在转换时背景会模糊并透明地显示第一个视图控制器,但模态视图控制器在完全加载后会变成黑色。 - Crashalot

25

我刚用Swift重新实现了Sebastian Hojas的解决方案:

1. 创建一个UIView扩展并添加以下方法:

extension UIView {
    func convertViewToImage() -> UIImage{
        UIGraphicsBeginImageContext(self.bounds.size);
        self.drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext();

        return image;
    }
}

2. 使用苹果的图像效果(我在这里找到了它的Swift重新实现:SwiftUIImageEffects),创建当前视图的图像并将其模糊。

var imageOfUnderlyingView = self.view.convertViewToImage()
imageOfUnderlyingView = imageOfUnderlyingView.applyBlurWithRadius(2, tintColor: UIColor(white: 0.0, alpha: 0.5), saturationDeltaFactor: 1.0, maskImage: nil)!

3. 将其设置为覆盖层的背景。

let backView = UIImageView(frame: self.view.frame)
backView.image = imageOfUnderlyingView
backView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
view.addSubview(backView)

15

我认为这是一个在iOS8中覆盖了所有内容并且带有漂亮模糊效果的模态视图控制器的最简单解决方案。

    UIViewController * contributeViewController = [[UIViewController alloc] init];

    UIBlurEffect * blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    UIVisualEffectView *beView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    beView.frame = self.view.bounds;

    contributeViewController.view.frame = self.view.bounds;
    contributeViewController.view.backgroundColor = [UIColor clearColor];
    [contributeViewController.view insertSubview:beView atIndex:0];
    contributeViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

    [self presentViewController:contributeViewController animated:YES completion:nil];

1
覆盖层似乎将添加在顶部视图层上。 - c9s
1
这个不能保持模糊状态吗?使用iOS 8的方法,在转换时背景会模糊并透明地显示第一个视图控制器,但模态视图控制器在完全加载后会变成黑色。- Crashalot 刚刚编辑 - Crashalot
@Crashalot,你有没有更改任何设置,比如将UIModalPresentationOverCurrentContext更改为全屏显示? - Andrew Plummer
1
补充一下,如果您不使用那种模态呈现样式,它会停止在模态出现后显示底部的VC,因此它会变成“黑色”(底部没有任何内容)。要添加@Crashalot。 - Andrew Plummer

12

iOS 7 SDK中没有提供可让您“冰冻”底层视图控制器的API。

我的解决方法是将底层视图渲染为图像,然后将其冰冻并将其设置为正在呈现的视图的背景。

苹果公司为此提供了一个很好的示例:https://developer.apple.com/downloads/index.action?name=WWDC%202013

您需要的项目名为iOS_RunningWithASnap


你如何在模态视图弹出时保留后面的ViewController?在我的情况下,后面的VC消失了。 - João Nunes
你不需要,因为后面的视图控制器只是模态视图控制器上的一个毛玻璃图像。 - rckoenes

10

一个更简单的方法来实现这个功能(基于Andrew Plummer的回答),使用Interface Builder(同时它也消除了在Andrew的答案中出现的副作用):

  • 在IB中将Visual Effect View添加到您的View Controller下的其他视图中;
  • 从Visual Effect View到顶部(父)View,设置所有约束为0的顶部、底部、左侧和右侧约束;
  • 设置模糊样式;
  • 在您呈现新的精美视图控制器时添加代码:

UIViewController *fancyViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"yourStoryboardIDFOrViewController"];

fancyViewController.view.backgroundColor = [UIColor clearColor];
fancyViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

[self presentViewController:fancyViewController
                   animated:YES
                 completion:nil];
实际上,第二行和第三行非常重要-否则控制器会闪烁然后变黑。

什么是mainButtonViewController? - christijk
@christijk,现在应该是fancyViewController了。感谢您指出。 - Andrei Konstantinov

9
自 iOS 8 开始,这个功能可以正常使用:
        let vc = UIViewController()
        vc.view = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
        vc.modalPresentationStyle = .OverFullScreen

        let nc = UINavigationController(rootViewController: vc)
        nc.modalPresentationStyle = .OverFullScreen

        presentViewController(nc, animated: true, completion: nil)

关键在于 .OverFullScreen 标志以及确保 viewControllers 具有模糊的 UIVisualEffectView,这是第一个可见的视图。

6

正如@rckoenes所说,苹果没有提供相关的框架来实现这个效果。但是有些人已经构建了很好的替代方案,例如这个:

https://github.com/JagCesar/iOS-blur/


5

5

5

不要将viewController以modalView的形式呈现,而是可以将其作为子viewController添加,并创建自定义动画。然后只需要在viewDidLoad中将viewController的默认视图更改为UIToolBar即可。

这样可以尽可能地模仿App Store的模糊模态视图。


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