UIGestureRecognizer not receiving touches during UIScrollView deceleration - iphone

I've been trying to create a UITextView subclass that handles swiping away the keyboard like in the Message.app.
I have a UIPanGestureRecognizer added to the keyWindow of my app, and the gesture delegate is configured for shouldRecognizeSimultaneouslyWithGestureRecognizer. Everything works fine except for when the UIScrollView is decelerating, during that phase it is possible to pan without the touches being registered.
You can take a look at a very simple github sample project here.
I have tried adding the UIPanGestureRecognizer directly to the viewController.view and to the scrollView, same issue occurs. I have also tried setting scrollView.panGestureRecognizer requireGestureRecognizerToFail: with my UITextView subclass gesture recognizer.
Any ideas as to why this may be happening?

Instead of creating a new UIPanGestureRecognizer, maybe you could use the one on the UIScrollView, and add your own pan logic to that gesture recognizer with - (void)addTarget:(id)target action:(SEL)action.

Related

Gesture is not working when used on transparent UIView when subclassed to detect objects behind it

Hi all,
I am having some issue with detecting touches. Please refer image where yellow and brown are my UIView which is subclassed to detect the transparent touches. I have added three gesture recognizers pan, tap and rotation on that UIViews, but when I subclass UIView and override the - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event method to detect all the Imageviews added, gesture recognizers stop working outside the ImageView. And if I am not using subclass then it's unable to detect touches for ImageView on the yellow UIView. I tried the solution from this link
Forwarding UIGesture to views behind
though it is not the same as my requirement, but it didn't help! Any help/hint is appreciated! Thanks in advance.
I have resolved the issue myself. I achieved the my target by applying gesture recognizers on superview not separate for each uiimageview or the colored uiviews. I have added uiviews on superview and now gesture is getting applied to imageview also. And also changed the code in gesture actions so that gesture will get applied to touched imageview and not on superview.
Try implementing gestureRecognizerShould begin in your subclass, test to see if the class of the recognizer is those classes [gestureRecognizer class] == [UITapGestureRecognizer class] for example, and return yes if it is.
http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/gestureRecognizerShouldBegin:
The only way I've found to fix this is to add your stack of views as children to a UIView (A). It should be the same size as your transparent view/ all of the child views on your stack. You should implement the gesture recogniser in the view controller if and connect (A) as the iboutlet (just drag and drop a gesture recogniser onto A in interface builder for example).
(View Controller)
|->(A)
|->(1) Need gesture
|->(2) Need another gesture
|->(3) Transparent (messing everything up)
Connect the gesture handlers to the appropriate children of A who need to handle them.
For View Controller
#interface AUIViewController : UIViewController <bla, bla, UIGestureRecognizerDelegate >
For (1)
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer{/*yada yada*/}
In my opinion, this is an apple bug.
My answer is pretty much this but it is a work around for what is in my opinion, a bug.
P.S, sorry I didn't fix this without using interface builder. Hope its still helpful

Zoomable UIScrollView with UIButtons capturing touches

I have a UIScrollView and I'm implementing the viewForZoomingInScrollView: delegate method which returns a UIImage which the user can zoom and pan. I've also got some UIButtons as sub views of the UIScrollView which I'm using as annotations, like Google Maps.
The problem I'm having is that a lot of the UIImage can be obscured by the UIButtons when zoomed right out. When trying to pinch to zoom the UIButtons are receiving the touch event instead and the zoom is not happening. You end up having to carefully place your fingers in clear space to zoom.
I note the Google Maps app seems to work ok when there are lots of annotation views, you can still pinch.
I guess I need to priorities the touches, the UIScrollView needs to respond to pinches and pans, while the buttons just taps.
Anyone have experience of this?
I had this exact issue, and it was kind of weird. It wasn't due to any gesture recognizer on the button, it was the UIScrollView's pinch gesture recognizer that was being forwarded to the UIButton for some reason. Also, the UIButton was responding to certain UIGestureRecognizerDelegate calls (like -gestureRecognizerShouldBegin:) but not others (like -gestureRecognizer:shouldReceiveTouch:). It's like the UIScrollView was selectively forwarding some delegate calls to the UIButton and some not.
I finally found a very easy way to solve this issue:
yourScrollView.pinchGestureRecognizer.delaysTouchesBegan = YES;
yourScrollView.pinchGestureRecognizer.delaysTouchesEnded = YES;
Luckily, the default pinch gesture recognizer on UIScrollView's are publicly accessible, and the two delaysTouches property are NO by default. When you set them to YES, if the gesture recognizer could possibly or does recognize a pinch gesture even when it starts on top of a UIButton, it won't forward those touches to the UIButton, and the UIButtons will no longer interfere with the UIScrollView's zooming.
try this
UIGestureRecognizer* tapRecognizer = nil;
for (UIGestureRecognizer* recognizer in yourButton) {
if ( ![recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
[yourButton removeGestureRecognizer:recognizer];
break;
}
}
so you remove all the gesture recognizers from the button different from UITapGestureRecognizer
take a look at UIView's hitTest:withEvent: method. Inside that method youll need to check for which view you want to return. The view you return will be the one recieving the touches. for example, you can subclass the button and override that method to return the ImageView for your particular scenario.
I fixed this problem in a different way, but this might not be your case.
My buttons were added on an image view, the image view being added by itself to another container view. In the:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
... method, I returned the image view - bad. Changing to return my very first container view in hierarchy fixed the touches.

UITapGestureRecognizer interefering with UIPinchGestureRecognizer

I have a view controller that attaches a UITapGestureRecognizer to its main UIView, and enables the user to tap the screen to make the status, navigation, and tool bars reappear / disappear (like the photos app). I also have a UIScrollView attached to the main UIView which implements zooming and thus has its own UIPinchGestureRecognizer and UIPanGestureRecognizer to implement scrolling and zooming.
The problem I'm having, is when going to zoom / scroll the UIScrollView, it's very sensitive to picking up the UITapGestureRecognizer which is attached to the main UIView. It seems a lot of the time the UITapGestureRecognizer gets triggered when it shouldn't. Anyone have any ideas on how to fix this for versions of ios below 5.0? Is there someway I can override the simultaneous gestures delegate method for the UIGestureRecognizerDelegate in the UIScrollView and prevent the UITapGestureRecognizer from firing during other gestures?
Use the requireGestureRecognizerToFail: method.
[tapGestureRecognizer requireGestureRecognizerToFail:pinchGestureRecognizer];
This call tells the tap recognizer to wait for the pinch recognizer to fail.

How to detect horizontal swipe gesture on the custom UIScrollView?

I created custom UIScrollView and add UIImageView.
I want to detect horizontal swipe gesture on the UIScrollView, but I cannot do it.
I cannot find any other references in my case.
I found only following url, but it's not real detecting gesture.
How to recognize swipe gesture in UIScrollView
I've not any zoom effect.
Please help me.
Doesn't one of the UIScrollViewDelegate methods such as [UIScrollViewDelegate scrollViewDidScroll:] work for you? I don't know your specific case, but standard way of detecting swipe action in UIScrollView should be through its delegate.

How to pass a 'tap' to UIButton that is underneath UIView with UISwipeGestureRecognizer?

I have a UIButton underneath a (transparent) UIView. The UIView above has a UISwipeGestureRecognizer added to it, and that is its only purpose - to detect certain swipe gestures. I want all other touches to be ignored by that UIView, and passed to other views (such as my UIButton underneath). Currently, the UIView above seems to be detecting the tap (for example), doing nothing (as it should be), and not letting the UIButton underneath get a chance to respond.
I would prefer not to implement my own swipe recognizer, if possible. Any solutions / advice? I basically just want to know how to tell a UIView to pay attention to only a certain type of added gesture recognizer, and ignore (and thus let through to views behind) all other touches.
Have you set:
mySwipeGesture.cancelsTouchesInView = NO;
to allow the touches to be sent to the view hierarchy as well as the gesture?
Additionally, ensure that the view on top is:
theTransparentView.opaque = NO;
theTransparentView.userInteractionEnabled = YES;
I've had pretty good success attaching gestures to the parent view without needing to create a transparent subview on top for the gesture. Are you sure you need to do that?
I must have just been in a funk yesterday - I woke up with a simple solution today. Add the UISwipeGesture to a view which is a superview to both the UIView and the UIButton. Then, when processing those swipes, figure out where the swipe originated, and whether that point is in the frame of where I used to have the UIView. (As I mentioned, the only reason for the existence of the UIView was to define a target area for these swipe gestures.)
Can't you put your button on top of the view and add gesture recognisers to that button too?
In the end, your UIButton inherits form UIView via UIControl. Therefore there is practically nothing that you could do with a view but not with a button.
In my case, I fixed it by not using a button, but rather a UITapGestureRecognizer. My pan gesture recognizer was added to the background view, and the tap gesture was added to a view above it.