Dismiss does not work correctly UIScrollView and UITableView

108 Views Asked by At

I have a UIViewController class that is presented over full screen On it I have a scrollview and a stackview with a uiview and a table

view.addSubview(scrollView)
scrollView.addSubview(stackView)
stackView.addArrangedSubview(view1)
stackView.addArrangedSubview(tableView)

scrollView has a TapGestureRecognizer

func settings() {
    let gestureRec = UITapGestureRecognizer(target: self, action: #selector(close))
    gestureRec.cancelsTouchesInView = false
    gestureRec.numberOfTapsRequired = 1
    gestureRec.delegate = self
    
    scrollView.addGestureRecognizer(gestureRec)
}

@objc func close() {
    dismiss(animated: false)
}

Now if you click on any place, the screen closes, even if it is a tableView, how can I fix it? The screen needs to be closed only when you click on scroll, the table inside StackView should work fine

I tried to work with UIGestureRecognizer Delegate,override methods, determine the location of the tap

1

There are 1 best solutions below

0
Kunal Kamble On

From what I gathered from your question, you have a parent view (scroll view) and a child view (stack view), and you only want to perform an action when the user taps on the parent view and not its children.

One solution you can try is to override gestureRecognizer:shouldReceiveTouch: and return true if the touch is in the desired place. Here's an example:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)
  -> Bool
{
  return touch.view?.isEqual(scrollView) ?? false
}

Another way is to use hitTest(_:with:) to determine the farthest descendant of the receiver in the view hierarchy (including itself) that contains the specified point (in our case, the touch). For your use case, if hitTest returns the scroll view, then you can confidently say that the user did not tap on the stack view. Here's an example:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)
  -> Bool
{
  let hitView = scrollView.hitTest(touch.location(in: scrollView), with: nil)
  return hitView?.isEqual(scrollView) ?? false
}

Hope this helps!