0

I'm following this tutorial to make a overlay view controller, using frameOfPresentedViewInContainerView in iOS 8, but I'm curious, how would I then close this view controller based on tapping outside of the visible area?

Doug Smith
  • 29,668
  • 57
  • 204
  • 388

1 Answers1

1

There is one popular solution where you add a UITapGestureRecognizer to the window and then perform a hit test to check if the tap was outside the modal view frame.

However, since you use UIPresentationController, I'd suggest going for the more versatile solution:

In your UIPresentationController subclass override presentationTransitionWillBegin:

override func presentationTransitionWillBegin() {
    var dimView = UIView() // Use your specific subclass here
    dimView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5) // No need for this if you have your subclass defined in IB

    self.containerView?.addSubview(dimView)
    dimView.snp_makeConstraints { (make) -> Void in // I use SnapKit to avoid the NSLayoutConstraint nonsense
        make.edges.equalTo(self.containerView!)
    }
    dimView.addSubview(self.presentedViewController.view)

    let transitionCoordinator = self.presentedViewController.transitionCoordinator()

    dimView.alpha = 0
    transitionCoordinator?.animateAlongsideTransition({ (context) -> Void in
        dimView.alpha = 1
    }, completion: { (context) -> Void in

        })
    }

This will give you a proper dimming view that will be placed behind your presented view controller. Now it's totally up to you what you do with that dimming view, you can style it or place buttons there:

enter image description here

I recommend defining this view in the interface builder, it makes it a lot easier, the example may look like this:

class MyDimView: UIView {
    var onPrevAction: (() -> ())?
    var onNextAction: (() -> ())?
    var onTapAction: (() -> ())?

    @IBOutlet private var prevButton: UIButton!
    @IBOutlet private var nextButton: UIButton!
    @IBOutlet private var button: UIButton!

    @IBAction private func onPrevButtonTouched() {
        if let prevAction = self.onPrevAction {
            prevAction()
        }
    }

    @IBAction private func onNextButtonTouched() {
        if let nextAction = self.onNextAction {
            nextAction()
        }
    }

    @IBAction private func onViewTouched() {
        if let tapAction = self.onTapAction {
            tapAction()
        }
    }
}

This way you have the absolute control over what happens outside or your presented view controller.

Community
  • 1
  • 1
lawicko
  • 7,246
  • 3
  • 37
  • 49