Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gestures conflict with an overlay's inner scroll view #75

Closed
pavelhiq opened this issue Nov 16, 2020 · 4 comments
Closed

Gestures conflict with an overlay's inner scroll view #75

pavelhiq opened this issue Nov 16, 2020 · 4 comments

Comments

@pavelhiq
Copy link

Using the overlay with the .expandableHeight style, I came across a scenario where I would not want to use the overlay's inner scroll view as driving for the overlay. That is for two reasons:

  • when in collapsed state, it should not be possible to scroll the content of the overlay's inner scroll view, and hence it cannot drive when disabled
  • even when enabled, but at the same time representing some kind of empty state (contentSize.height < bounds.height), it seems to be not possible to drag the overlay because there is nothing to actually scroll in the driving scroll view

If I skip setting the drivingScrollView (or implementing the appropriate delegate method) however, the overlay's own pan gesture gets ignored whenever the inner scroll view is enabled. As a result, it becomes not possible to e.g. collapse the expanded overlay.

After exploring the code a bit and with some experiments, I found that the problem can be resolved by allowing the overlay's private pan gesture to be recognized simultaneously with the pan gesture of the inner scroll view on certain condition. In particular, by allowing recognition when the inner scroll view reaches the top of its content, like this:

// PanGestureOverlayTranslationDriver.swift
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if panGestureRecognizer.drivingScrollView == nil,
           gestureRecognizer is OverlayTranslationGestureRecognizer,
           otherGestureRecognizer is UIPanGestureRecognizer,
           let scrollView = otherGestureRecognizer.view as? UIScrollView  {
            return scrollView.contentOffset.y <= 0
        }
        return false
    }

@gaetanzanella do you think adding the above change makes sense? or does that break the library's intent somehow? 🤔 please let me know and I can make a PR out of it, or otherwise just fork 🙂

@gaetanzanella
Copy link
Contributor

Hi @pavelhiq! thanks for the detailed issue.

Did you try to use the overlayContainerViewController(:shouldStartDraggingOverlay:at:in:) method before modifying shouldRecognizeSimultaneouslyWith?

even when enabled, but at the same time representing some kind of empty state (contentSize.height < bounds.height), it seems to be not possible to drag the overlay because there is nothing to actually scroll in the driving scroll view

Did you try to set scrollView.alwaysBounceVertical = true?

@pavelhiq
Copy link
Author

Wow, thanks for a swift reply @gaetanzanella!

Yes, I did try that overlayContainerViewController(:shouldStartDraggingOverlay:at:in:) first, but with no success. Also noticed that according to the doc it is not called when an inner scroll view is involved:

If the gesture begins in the scroll view specified in overlayContainerViewController(_:, scrollViewDrivingOverlay:),
the gesture is aborted and this method is not called.

Im not sure if setting scrollView.alwaysBounceVertical = true can help at all with scrolling disabled (also tried it).

Although I should mention that with drivingScrollView set, the overlay is not completely dead but I need to draw/swipe really "hard" to make the translation happen 🙂 My guess is that it can happen because of the private pan gesture recognizer requiring the driving scroll view's gestures to fail in shouldRequireFailure(of:)?

@gaetanzanella
Copy link
Contributor

gaetanzanella commented Nov 16, 2020

Could you describe the exact scenario? I am not sure to understand what you are looking for. A sample code or a video of the problem might help.

I came across a scenario where I would not want to use the overlay's inner scroll view as driving for the overlay

You can reset the drivingScrollView (container.drivingScrollView = nil) whenever you want if you use the drivingScrollView property instead of the delegate method. In such scenario, shouldStartDraggingOverlay: is called.

Im not sure if setting scrollView.alwaysBounceVertical = true can help at all with scrolling disabled (also tried it).

You said even when enabled,

@gaetanzanella
Copy link
Contributor

Your case looks interesting. I'm not surprised there might be a potential gesture conflict…

// PanGestureOverlayTranslationDriver.swift
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if panGestureRecognizer.drivingScrollView == nil,
           gestureRecognizer is OverlayTranslationGestureRecognizer,
           otherGestureRecognizer is UIPanGestureRecognizer,
           let scrollView = otherGestureRecognizer.view as? UIScrollView  {
            return scrollView.contentOffset.y <= 0
        }
        return false
    }

does not look like a great solution because someone might want another condition one day, right?

We should find a customizable solution instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants