make superview respond to subView's UIPanGesture in some cases - ios

I have a scrollView and it contains a subView. SubView has a panGesture added to it.
What I want:
I need pangesture to work on subview only if the panning is done vertically. If the panning happens horizontally, I want the scrollView to respond for the panning instead of subview. How can I acheive this
Note: Iam able to find programatically when the panning happens horizontally.

There are several ways to do this:
Depending on what your subview does, you maybe able to replace it with a scrollview and lock it to scroll only vertically. (while the super should scroll only horizontally).
You can try feeding the touch information from the subview to it's superview if the pan gesture is moving horizontally. You could do this using a delegate pattern or, if you know what you're superview is, just access superview in your subview. However, this creates a strong coupling between the two views and probably shouldn't be done. It would be fragile and many would consider it code smell.
(best option) - Subclass UIGestureRecognizer and create your own gesture recognizer that only recognizes vertical movement. Use that instead of the UIPanGestureRecognizer.
Option 3 is the best, but probably the most work. You'll want to read Apple's docs on subclassing UIGestureRecognizer: Apple Docs - UIGestureRecognizer.
I've also written my own drag gesture recognizer, FlxDragGestureRecognizer.m, FlxDragGestureRecognizer.h (similar to a pan gesture recognizer), which you can use if you'd like, or take a look at to get a good idea of how to subclass UIGestureRecognizer. You can use this class to recognize touches moving only in certain directions, otherwise it will fail (which will allow other gesture recognizer to recognizer, like the scrollview). It also has a lot of other customizations and information it gathers, like velocity.

Since you already know how to detect the panning, then in you will need to implement a delegate protocol in your superview, a delegate property in your subview and assign your superview as a delegate for your subview.
when detecting horizontal panning, call the delegate method, when detecting vertical panning, implement what you want in the subview.

Related

Detect continuous touch position in view with UIScrollView still active

I am interested in getting the touch location (e.g. something that is, or mimics touchesMoved) in a view controller's view while still keeping a UIScrollView subview enabled. Since all of the touchesDidSomething methods are consumed by the UIScrollView, my hope is that there's a roundabout way of achieving this.
Here are a few things I've tried:
Subclassing a UIScrollView, overriding it's touchesMoved method and passing that touch information to a custom delegate method in my scrollView's view controller. --> This actually works if I deselect "cancellable content touches" and "delays content touches" on my scroll view but it prevents my scroll view from scrolling.
Using the same tactic as above but with a subclassed UIView as a sibling to my UIScrollView. Hence, the hierarchy is as follows:
view
UIScrollView
Subview
Subview
CustomUIView <-- custom UIView that calls delegate
Both of these methods work to the extent that I can grab the data, but at the expense of my scroll view not scrolling anymore. I know I can grab the location of a touch event in a UIScrollView similar to a touchesBegan while the scrollView continues to work but I haven't found a way to get continuous touch events while scrolling. Is this possible?
Here's an illustration of what I'm after:
For some metadata as to why I'm looking for this and why grabbing something like scrollViewDidScroll's contentOffset.x won't work, I'm specifically interested in when the scrollView has scrolled to the end (or beginning) and a user is attempting to keep swiping forward (or backward) even though the scrollView can't scroll in the swiped direction anymore. When this happens I want to detect the forward (or backward) swipe motion to initiate a slick transition to another view.
I solved this by adding a panning gesture recognizer to my view and using it's translationInView method (UISwipeGestureRecognizer doesn't have this method). Example below
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(myMethod(_:)))
panGesture.delegate = self
self.addGestureRecognizer(panGesture)
func myMethod(sender: UIPanGestureRecognizer) {
// sender.translationInView(self).x
}
Also making sure to return true for shouldRecognizeSimultaneouslyWithGestureRecognizer in the UIGestureRegognizerDelegate to account for the scrollView.

UIScrollView scrolling using a gesture on the overlaid view

Consider the view hierarchy in the figure below:
OverlayView is simply a control view that has some custom controls on it. It also has multiple tap/swipe gesture recognizers. The ScrollView is the scroll view that needs to be scrolled based on the interactions with OverlayView. The OverlayView has the same frame as that of the ScrollView.
I need a way to add some kind of swipe/pan gesture setup configured for the OverlayView such that I can scroll the underlying ScrollView as if I am interacting with it.
There seems to be two different approaches:
Recognize the gesture on the OverlayView and pass it to ScrollView. But I am unsure what gestures to use and how to make ScrollView interact with them.
Ignore all the touches on the OverlayView unless they are on the controls. Pass these touches to the underlying ScrollView. This seems like the easier approach; but I am not sure how to proceed with this either.
Does anybody have any kind of sample code for some project or a similar exercise they worked on before? If not, any pointers whatsoever?
Option 2 is what I was going to recommend. There is a method you can override called hitTest:withEvent: on UIView.
You return a view from it. So if the touch needs to go through to the scroll view then return the scroll view. Else return self.

UIScrollView - scroll or swipe?

In my app I have a UIScrollView and I need to swipe left and right from one picture to the next, but I also need to recognize a scroll.
How do I differentiate between a scroll and a swipe with UIScrollView?
I believe you're actually looking for is an implementation of UIScrollView with Paging, as you do not need to handle the touch events yourself, or determine if they are scrolls or swipes.
The Apple Documentation on Scroll Views and Paging Mode should help you get started
Look into the UIScrollView Delegate Methods. ScrollView can detect different types of actions drag etc or add swipeGesture directly to the scroll view
StackOverflow has questions already on this
iOS: UIScrollView detecting Swipe Gesture
Setting up UIScrollView to swipe between 3 view controllers
How to recognize swipe gesture in UIScrollView

Cancel UIGestureRecognizer if subview contains gesture?

I was originally using the UITouch methods (touchesMoved: withEvent:) in order to detect the movement in a view. Due to the fact that it seemed not to update often enough I switched to using a UIPanGestureRecognizer (though this didn't actually fix the initial problem).
After using this the touches received for movements responded no matter what it was touching (different subviews) which I actually prefer. However now I have an issue with all the subviews which have movement. I need the gesture recognizer to still move the view even while touching subviews, however if the subview also moves in this direction (left/right) I need my recognizer to cancel.
It seems like gestureRecognizerShouldBegin: might be somewhere to start, but in my case, I cannot account for all subviews.
Is it possible to make pan gesture recognizer cancel if the subview (i.e. another pan recognizer, UISlider, horizontal scrollview, etc.) touched needs to be moved in left/right directions without having to account for each subview individually?

Can I pass a pinch gesture recognizer to a ScrollView to have it zoom?

I wrote a custom pinch gesture recognizer for my ScrollView's zooming, and I handle pinch touches in a method in my view controller.
But in some cases, I want the ScrollView to behave exactly as it would normally behave (if it used the standard pinch gesture recognizer that comes with ScrollView).
Is there some way that in such cases I can pass my custom gesture recognizer to the ScrollView and it would use that recognizer to scale the view as it normally would?
Could I pass the gesture recognizer to the selector that is triggered by pinch actions?
I have not tried this, but here's an idea:
When you set your own gestureRecognizer, store the ScrollView's pinchGestureRecognizer in an iVar. You should then be able to dynamically exchange your gestureRecognizer and the original one.
As of iOS 5 UIScrollView exposes a pinchGestureRecognizer property, but this is read-only. To get it to use your own instead you have to subclass UIScrollView and overwrite this property hoping that internally UIScrollView also uses this property to get the gesture recognizer to add when zooming is enabled.
However it is quite dangerous messing with scroll view's gesture recognizers, especially to modify their behavior. Even just having a different delegate will trigger an exception. So proceed at your own risk.

Resources