UIBlurEffect in a custom modal presentation

863 views Asked by At

I am currently presenting a view controller over a third of the screen with a custom UIPresentationController. In my UIPresentationController, I wrap the presentedViewController in a few views to get rounded corners and a shadow (like in Apple's Custom Transitions sample app). I recently added a UIVisualEffectView with a UIBlurEffect to the presentedViewController hierarchy, but it is displaying weird. The view is now semi-transparent, but not blurred.

I think this is because the blur effect is being applied properly, but because it's a modal presentation it is not seeing the view behind and therefor unable to blur it. Any thoughts? Here is the related code in override func presentationTransitionWillBegin()

    // Wrap the presented view controller's view in an intermediate hierarchy
    // that applies a shadow and rounded corners to the top-left and top-right
    // edges.  The final effect is built using three intermediate views.
    //
    // presentationWrapperView              <- shadow
    //   |- presentationRoundedCornerView   <- rounded corners (masksToBounds)
    //        |- presentedViewControllerWrapperView
    //             |- presentedViewControllerView (presentedViewController.view)
    //
    // SEE ALSO: The note in AAPLCustomPresentationSecondViewController.m.


    let presentationWrapperView = UIView(frame: frameOfPresentedViewInContainerView)
    presentationWrapperView.layer.shadowOpacity = 0.44
    presentationWrapperView.layer.shadowRadius = 13
    presentationWrapperView.layer.shadowOffset = CGSize(width: 0, height: -6)
    self.presentationWrappingView = presentationWrapperView

    // presentationRoundedCornerView is CORNER_RADIUS points taller than the
    // height of the presented view controller's view.  This is because
    // the cornerRadius is applied to all corners of the view.  Since the
    // effect calls for only the top two corners to be rounded we size
    // the view such that the bottom CORNER_RADIUS points lie below
    // the bottom edge of the screen.
    let presentationRoundedCornerView = UIView(frame: UIEdgeInsetsInsetRect(presentationWrapperView.bounds, UIEdgeInsets(top: 0, left: 0, bottom: -CORNER_RADIUS, right: 0)))
    presentationRoundedCornerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    presentationRoundedCornerView.layer.cornerRadius = CORNER_RADIUS
    presentationRoundedCornerView.layer.masksToBounds = true

    // To undo the extra height added to presentationRoundedCornerView,
    // presentedViewControllerWrapperView is inset by CORNER_RADIUS points.
    // This also matches the size of presentedViewControllerWrapperView's
    // bounds to the size of -frameOfPresentedViewInContainerView.
    let presentedViewControllerWrapperView = UIView(frame: UIEdgeInsetsInsetRect(presentationRoundedCornerView.bounds, UIEdgeInsets(top: 0, left: 0, bottom: CORNER_RADIUS, right: 0)))
    presentedViewControllerWrapperView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    let blurWrapperView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
    blurWrapperView.autoresizingMask =  [.flexibleWidth, .flexibleHeight]
    blurWrapperView.frame = presentedViewControllerWrapperView.bounds

    // Add presentedViewControllerView -> presentedViewControllerWrapperView.
    presentedViewControllerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    presentedViewControllerView.frame = blurWrapperView.bounds
    blurWrapperView.contentView.addSubview(presentedViewControllerView)

    presentedViewControllerWrapperView.addSubview(blurWrapperView)
    // Add presentedViewControllerWrapperView -> presentationRoundedCornerView.
    presentationRoundedCornerView.addSubview(presentedViewControllerWrapperView)

    // Add presentationRoundedCornerView -> presentationWrapperView.
    presentationWrapperView.addSubview(presentationRoundedCornerView)
2

There are 2 answers

2
Mihai Fratu On

As I said in the comment above, from my experience, playing with the presentationStyle property of the UIPresentationController allows you to define how the views behind the presented one are handled once that happen. See here more info about it. The property itself is of type UIModalPresentationStyle and you can see it's available values here.

In my opinion it seems that overCurrentContext it's the value you want. From Apple's documentation:

The views beneath the presented content are not removed from the view hierarchy when the presentation finishes. So if the presented view controller does not fill the screen with opaque content, the underlying content shows through.

In my view that means that your blur view will then have something to blur.

Update


Also, you could try this, too even though Apple's documentation seems off. I think the default value of the property is true not false as mentioned in there.

0
denvdancsk On

I'm assuming you are testing this on the simulator, right? If so make sure to check the simulator's Graphic's Quality Override setting and set it to High Quality. That should do the trick for you.