Noah Iarrobino
Noah Iarrobino

Reputation: 1543

Dismiss UIView within ViewController by tapping outside of UIView

I'm presenting a UIView over my ViewController which contains a table view that covers the whole view controller. I want to dismiss the UIView when tapping outside of the UIView, but have not found anything that helps the cause. This is what I'm trying to do, and it should work but it's not registering touches even if the UIView is not presented. Anyone dealt with a similar issue?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch: UITouch? = touches.first

        if touch?.view != fullSessionView {
            fullSessionView?.removeFromSuperview()
        }
    }

Upvotes: 1

Views: 2961

Answers (4)

islam XDeveloper
islam XDeveloper

Reputation: 500

100% Working Good

override func viewDidLoad() {
    super.viewDidLoad()
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideView))
    tapGesture.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tapGesture)

    self.view.backgroundColor = .clear

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.18) {
        self.view.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.3111622432)
    }
}
@objc func hideView() {
    self.view.backgroundColor = .clear
    
    self.dismiss(animated: true)
}

Upvotes: -1

Apps Maven
Apps Maven

Reputation: 1410

You need to initialize UITapGestureRecognizer with a target and action to your view to be added, like so:

let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
myView.addGestureRecognizer(tap)
Then, you should implement the handler, which will be called each time when a tap event occurs:
@objc func handleTap(_ sender: UITapGestureRecognizer? = nil) {
    self.removefromSuperview() // this will remove added view from parent view
}

Upvotes: 2

pietrorea
pietrorea

Reputation: 898

First, I'd try to see if any of the built-in presentation styles could work for you. But you'd have to embed your view in a view controller.

If you want to stick with a UIView you could try presenting your UIView on top of a transparent background UIView that covers the whole screen and attaching a UIGestureRecognizer to the transparent background.

Tapping the background would trigger a call back (via delegate, closure, etc) that would then remove your view.

Upvotes: 1

aheze
aheze

Reputation: 30228

You should always call super, like this:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event) /// always call the super

But anyway, you want to see if fullSessionView contains the touch. So instead of checking the view where the touch happened, you probably want to check the location of where the touch happened. Something like this:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)

    let touch = touches.first
    guard let location = touch?.location(in: fullSessionView) else { return }
    if !fullSessionView.frame.contains(location) {

         /// tapped outside fullSessionView
         fullSessionView?.removeFromSuperview()
    }
}

Upvotes: 0

Related Questions