iosuitapgesturerecognizeruipresentationcontroller

iOS - How to pass down tap gesture without changing the underneath UIViewController?


I have two view controllers, B is presented on top of A, but not full screen. I am using a UIPresentationController to custom B's frame. What I want is, when tap on A, B is dismissed and A responds to it's own tap gesture.

How to achieve this within B and the UIPresentationController, without touching A's code?

I tried to add a full screen background view for B, but don't know how to pass the tap gesture down without changing A.

enter image description here


Solution

  • Customize a background view, always return false for pointInside method to ignore the touch event and do whatever needed before return, such as dismiss B.

    class BackgroundView: UIView {
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            // anything you want
            return false
        }
    }
    

    Add the custom background view to the UIPresentationController. Set containerView's isUserInteractionEnabled to false, otherwise the UITransitionView will block the touch event to pass down.

    class MyPresentationController: UIPresentationController {
        var backgroundView: BackgroundView = BackgroundView()
        var containerFrame: CGRect = UIScreen.main.bounds
        
        override var frameOfPresentedViewInContainerView: CGRect {
            return CGRect(x: 0, y: 300, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 300)
        }
        
        override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
            super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
            self.backgroundView.backgroundColor = UIColor.yellow
            self.backgroundView.alpha = 0.5
            self.backgroundView.translatesAutoresizingMaskIntoConstraints = false
        }
        
        override func presentationTransitionWillBegin() {
            self.containerView?.addSubview(self.backgroundView)
            self.containerView?.isUserInteractionEnabled = false // !!!
        }
        
        override func containerViewDidLayoutSubviews() {
            super.containerViewDidLayoutSubviews()
            self.containerView?.frame = self.containerFrame
            self.backgroundView.frame = self.containerFrame
            self.presentedView?.frame = self.frameOfPresentedViewInContainerView
        }
    }