Reputation: 1082
I have a scrollView that is underneath an overlay view that covers the entire screen. On this overlay view, I have a mini view. I have attached a pan gesture to the overlayView, and when this pan gesture is dragged upwards/downwards, it animates the growing/shrinking of the mini view. My goal is, when I reach the bottom of the scrollView, if I do another swipe upwards, it would call the pan gesture of the overlayView to animate the miniView's growth. But, if I do a swipe downwards from this position, then it would scroll back up the scroll view like normal. My problem is that I can't figure out how to either keep the touches within my overlay view, or pass them to the scrollView, where it could scroll normally. I need to be able to somehow access a function, where it lets me use an if statement (if scrollView.isAtCertainPoint && swipeWasInCertainDirection), then choose whether to pass the movement to the scrollView or overlayView. Here is my view hierarchy:
-Parent View
-----Overlay View ----------ScrollView
---------Mini View (subview of overlayView)
I am trying to recreate the upwards/downwards swiping of the app Bumble, if that is helpful. Thanks in advance, I've been looking everywhere, but can't seem to find an a solution.
Upvotes: 3
Views: 1820
Reputation: 1082
Well, I figured out the answer to my own question. Not sure if this is the most efficient/cleanest way to do it, but it was the only way to get the desired effect. Here is my solution: In my overlayView, I overridded
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if miniView.frame.contains(point) || miniView.isOpen {
return true
}
//pass the tap onto other views
return false
}
This basically allowed me to say if the view should have userInteraction, which I based upon certain criteria (the tap was inside my miniView or the miniView had enlarged). But, when I return false, then it would let the touch pass through. If you do not have this method overrided and the overlayView had userInteractionEnabled, then the overlay view would literally eat all the touches. With this method, I am able to still keep the userInteractionEnabled on the overlayView, but decide when the touches should pass through to somewhere else.
Then, in my parentView, I added a pan gesture. I made parentView a UIGestureRecognizerDelegate, and implemented this function:
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
//if the final page is the first page (i.e. the user only has one pic), then we don't want swiping that could interfere with the card swipe.
if let pan = gestureRecognizer as? UIPanGestureRecognizer {
let velocity = pan.velocity(in: self)
let isVertical = abs(velocity.x) < abs(velocity.y)
let isUpwards = getPanDirection(velocity: velocity) == .up
return (theBumbleScrollView.isAtFinalPage && isVertical && isUpwards) || theBumbleDetailView.isOpen
}
return true
}
This allowed me to see when the pan gesture was about to begin, and depending on what I return (true or false), it would change the state to .failed for the pan gesture. Basically, canceling it the gesture. This is a helpful Stack OverFlow post on this: Limit UIView movement to only vertical or horizontal axis
Now, my pan gesture was failing according to my specified criteria, but I needed to tell my scrollView that its pan gesture could get to panning, if my custom pan gesture had failed. That is where this handy line came in require(toFail: ...):
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.isPanning(pan:)))
pan.delegate = self
self.addGestureRecognizer(pan)
theScrollView.panGestureRecognizer.require(toFail: pan)
When I set the pan gesture onto the parent view, I basically told the scroll view's pan gesture (which apple built in automatically) that it should be next in line should custom pan gesture fail.
That was the solution that allowed me to sometimes scroll on my scrollView but other times be able to scroll upon my overlayView. Hope I can save someone the day that it took me to figure this out. I also created a github repo of my sample project (names of views are different), if anyone would like to see the sample code. https://github.com/danielchangsoojones/Bumble-App-Clone/tree/master
Upvotes: 2