如何在使用自适应segue的UITableView中实现UIVisualEffectView

29

我想要实现UIVisualEffectView来对一个视图应用模糊效果,以显示在它后面的视图。

需要被背景模糊的视图是嵌入在UINavigationController中的UITableViewController,并且它将被以iOS 8自适应Segue(呈现为弹出窗口)的形式在iPad上呈现,或者在iPhone上以全屏模态形式呈现。当此视图控制器处于弹出窗口中时,我希望背景可以模糊弹出窗口下方的内容,当以全屏幕方式呈现时,我希望能够使前一个视图控制器的背景模糊。

我已经尝试过实现这个功能,但没有成功。我甚至无法让弹出窗口的模糊效果起作用。我认为以下代码应该可以解决问题:

//In viewDidLoad on the UITableViewController subclass:
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
effectView.frame = tableView.frame
tableView.addSubview(effectView)

我还尝试将子视图添加到tableView.backgroundView,尝试将backgroundView设置为我的effectView,尝试使用Autolayout约束而不是设置框架,但是没有任何效果。你能帮我实现想要的行为吗?

我想要达到的示例:
iPad 弹出窗口:
enter image description here

iPhone 模态呈现:
enter image description here

4个回答

48

我终于找到了一个解决方案。我必须创建两个单独的segue——一个用于仅在iPad上调用的Popover Presentation,另一个是Presentation Style设置为Over Full Screen(这很重要)的modal segue,用于iPhone。

在被呈现的表视图控制器中,在 viewDidLoad 中,此代码将应用所需的模糊效果(奖励是,仅当他们没有禁用透明效果时才应用):

if (!UIAccessibilityIsReduceTransparencyEnabled()) {
    tableView.backgroundColor = UIColor.clear
    let blurEffect = UIBlurEffect(style: .light)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    tableView.backgroundView = blurEffectView

    //if inside a popover
    if let popover = navigationController?.popoverPresentationController {
        popover.backgroundColor = UIColor.clear
    }

    //if you want translucent vibrant table view separator lines
    tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
}

这会使表格背景看起来与截图中一样。对于iPhone的技巧是确保它在屏幕上呈现,而对于iPad的技巧是在popoverPresentationController中删除backgroundColor


我没有看到“全屏幕”演示文稿样式。这只适用于iOS 8吗? - livingtech
2
@livingtech 是的。自适应转场(以及解决方案中使用的其他API)仅适用于iOS 8+。 - Jordan H
2
我还注意到iPad 2和iPad Retina模拟器不显示模糊效果,只会使视图半透明。所有其他模拟器都可以正常工作,包括iPhone 4s。只是不要被这个问题所困扰,因为我最初认为UIVisualEffectView无法正常工作。 - Dmitry
1
@yar1vn 随意添加答案 - Jordan H
加上它会使单元格在滚动时跳动。为什么会这样? - Tarvo Mäesepp
显示剩余9条评论

6

使用适应性添加模糊的快速示例:

extension ViewController: UIPopoverPresentationControllerDelegate {

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    // Grab the destination view controller and set the presentation delegate
    let viewController = segue.destinationViewController as UIViewController
    viewController.popoverPresentationController?.delegate = self
    viewController.presentationController?.delegate = self
  }

  // Note: Only called for FormSheet and Popover
  func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
    switch controller.presentedViewController {
    case let vc as PopoverViewController:
      return .None // Keep the popover in Compact screens
    default:
      return .OverFullScreen
    }
  }

  func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
    // This is a custom method on UIViewController
    controller.presentedViewController.createBlur()

    // Wrap in a Navigation Controller, the controller should add a title and bar buttons
    if !(presentedViewController is UINavigationController) {
      return UINavigationController(rootViewController: presentedViewController)
    }
  }
}

extension UIViewController {
  func createBlur(effectStyle: UIBlurEffectStyle = .Light) {
    if !UIAccessibilityIsReduceTransparencyEnabled() {
      view.backgroundColor = UIColor.clearColor()

      let blurView = UIVisualEffectView(effect: UIBlurEffect(style: effectStyle))
      blurView.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
      blurView.frame = view.bounds

      view.insertSubview(blurView, atIndex: 0)
    }
  }
}

extension UITableViewController {
  override func createBlur(effectStyle: UIBlurEffectStyle = defaultBlurEffectStyle) {
    if !UIAccessibilityIsReduceTransparencyEnabled() {
      tableView.backgroundColor = UIColor.clearColor()

      let blurEffect = UIBlurEffect(style: effectStyle)      
      tableView.backgroundView = UIVisualEffectView(effect: blurEffect)
      tableView.separatorEffect = UIVibrancyEffect(forBlurEffect: blurEffect)
    }
  }
}

5
我来晚了,但对我来说(在ios8+中),最好的解决方法是在Storyboard中选择UIVisualEffectView,并将其设置为ViewController的根视图。然后将tableview添加到其中。
要查找Visual Effect View,请转到右下角的组件选择器(不确定叫什么),然后搜索VisualEffectView。
这似乎是一种更简单的方法,并符合苹果尽可能在Storyboard上完成大部分工作的建议。

1

一个关于IOS 10 Swift 3的小改变

if #available(iOS 10.0, *) {
        let blurEffect = UIBlurEffect(style: .prominent)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        groupTable.backgroundView = blurEffectView

    } else {
        let blurEffect = UIBlurEffect(style: .dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        groupTable.backgroundView = blurEffectView

    }

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