Detect a touch outside of presented view to dismiss it

639 Views Asked by At

So I have a side menu that is presented when a button is clicked and I would like to know if u guys could help me find how I can detect if a click occurred outside of that side menu view so I can dismiss it. I have looked around for this and all I see are deprecated things and with errors, and I can't use any. Here is my animation code :

    import UIKit

 class SlideInTransition: NSObject, UIViewControllerAnimatedTransitioning {

var isPresenting = false

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.3
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    guard let toViewController = transitionContext.viewController(forKey: .to),
    let fromViewController = transitionContext.viewController(forKey: .from) else {return }
    
    let containerView = transitionContext.containerView
    
    let finalWidth = toViewController.view.bounds.width * 0.8
    let finalHeight = toViewController.view.bounds.height
    
    if isPresenting{
        
        containerView.addSubview(toViewController.view)
        
        toViewController.view.frame = CGRect(x: -finalWidth, y: 0, width: finalWidth, height: finalHeight)
    }
    
    let transform = {
        toViewController.view.transform = CGAffineTransform(translationX: finalWidth, y: 0)
    }
    
    let identity = {
        fromViewController.view.transform = .identity
    }
    
    
    let duration = transitionDuration(using: transitionContext)
    let isCancelled = transitionContext.transitionWasCancelled
    UIView.animate(withDuration: duration, animations: {
        self.isPresenting ? transform() : identity()
    }){(_) in
        transitionContext.completeTransition(!isCancelled)
    } 
}
}
1

There are 1 best solutions below

0
On

I actually have something like this in my app. What you can do is add a UIView() that covers your whole view. Make sure this view is in front of everything but the menu! Set the UIView() userInteraction to false. When the menu is shown, simply set the view to intractable. Then put a touch recognizer so that when its touched the menu goes away!

Something I also like to do with this is set the views background to black, with an alpha of like 0.25! Then when the menu is hidden, alpha is zero, when it shows, animate it to 0.25. it dims the background when the menu is shown so it'll be functional and design nice.

    class BackGroundView: UIView {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            SetUpView()
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func SetUpView(){
            backgroundColor = .black
            alpha = 0
            isUserInteractionEnabled = false
        }
        
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    // Here's where you would hide the menu


           
        }
            
  func MenuIsShown(menuWillShow: Bool)
    {
        if(menuWillShow){
            isUserInteractionEnabled = true
             UIView.animate(withDuration: 0.2) {
            alpha = 0.45
            }
        } else{
            isUserInteractionEnabled = false

             UIView.animate(withDuration: 0.2) {
            alpha = 0
            }
        }
    }
    
            
            func AddViewToScene(view: UIView){
             


            view.addSubview(self)
            translatesAutoresizingMaskIntoConstraints = false
            topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    
            
        }
        
        
    }

then you can call it doing something like:

    class ViewController: UIViewController{
    

    override func viewDidLoad() {
        super.viewDidLoad()
        

     let dimView = BackGroundView()
     dimView.AddViewToScene(view: view)

    }
    
   

}