Search code examples
iosswiftuiscrollviewtouchswiftui-scrollview

How to capture touch events from a UIScrollView when user is scrolling the screen vertically on iOS with Swift?


I'm new to the iOS development and Swift and I have the following problem:

I would like to capture touch events from the screen. I have no problems with doing this on regular views. Unfortunately, I encountered issues with the UIScrollView component. When user is tapping on the screen, long pressing on the screen or moving finger horizontally, then I'm able to capture touches, but when user is moving finger vertically and activating vertical scrolling at the same time, then I'm not able to capture touches.

I found a few threads on StackOverflow regarding similar issue, but solutions provided there did not resolve my problem.

Structure of my views is as follows:

+- View (top-level view)
   |
   |
   +--- UIScrollView
        |
        |
        +-- other views inside...

Here is my code:

class MyViewController : UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(myRecognizer)
  }
}

Gesture recognizer is added into the top-level view.

I also have basic custom implementation of the UIGestureRecognizer:

class MyRecognizer: UIGestureRecognizer {
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        // handle events...
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        // handle events...
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesEnded(touches, with: event)
        // handle events...
    }
}

What did I try to do to solve this issue?

  • setting parameter scrollView.canCancelContentTouches = false - didn't help
  • setting parameter scrollView.isScrollEnabled = false - I was able to capture all touch events, but scrollView stopped working - didn't help
  • adding gesture recognizer to the scrollView and removing it from the top-level view - didn't help
  • adding gesture recognizer both to the scrollView and the top-level view - didn't help
  • setting parameter scrollView.isUserInteractionEnabled = false - I was able to capture all touch events, but scrollView and all UI components stopped working - didn't help
  • reordering calls in MyRecognizer class: handling events first and then calling method from the upper class super.touches... - didn't help

Right now, I have no idea what else I can do to capture touch events inside the UIScrollView while user is scrolling the screen vertically.

Any suggestions or help are appreciated!

Regards,

Piotr


Solution

  • So UIScrollView has its own set of gestures that have cancelsTouchesInView set to true by default. Try setting this property to false for each gesture in the scrollview like so:

    for gesture in scrollView.gestureRecognizers ?? [] {
        gesture.cancelsTouchesInView = false
    }
    

    EDIT:

    Solution to this problem is creating a separate custom UIScrollView and capture touches inside it. It is described in details in this thread: https://stackoverflow.com/a/70594220/10953499 (also linked in the comment).