touchesBegan method not called when scrolling in UIScrollView - iphone

I noticed touchesBegan method is not called in UIScrollView if i immediately place my finger on it and scroll. touchesBegan only gets called after i place my finger for a certain time duration before scrolling. Shouldn't touchesBegan always be called whenever there is a touch on the UIScrollView?

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyBoard:)];
[scrollView addGestureRecognizer:gestureRecognizer];
-(void) hideKeyBoard:(id) sender
{
// Do whatever such as hiding the keyboard
}

I believe that UIScrollView intercepts these events, for the purpose of figuring out if you are going to be scrolling the containing view. Actually, it looks like it gets them first (which is opposite normal processing, where the deepest subview gets them first) so that it can figure out if there is a scroll or pinch gesture. See How does UIScrollView steal touches from its subviews?

Related

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.

UIGestureRecognizers for view in a scroll view

I'm using a few UIGestureRecognizers to pan, rotate and scale a view, which resides inside a scroll view.
My problem is that sometimes the scroll view eats the touches before the gesture recognizers do, so when this happens I end up zooming the scroll view instead of dragging the view. (It doesn't happen all the time. I still can't describe how to reproduce this behavior).
I'm pretty sure this can be solved in some way. For example MPMoviePlayerController doesn't have this problem: in fact, you can put it in a scroll view, and when you pinch it, it works just fine (i.e. it doesn't zoom the outer scroll view too). Does anyone know how does MPMoviePlayerController achieve this?
I've already searched for answers on SO, with no results. Thanks!
Disclaimer: This is just an idea, I haven't tested this.
UIGestureRecognizerDelegate defines gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:. You could try implementing this on your gesture recognizer delegate. This won't prevent the scroll view from zooming. To prevent zooming you could try temporary setting maximumZoomScale minimumZoomScale to zoomScale in the recognizer action method.
At a guess your rotation is conflicting with zoom - both probably require two touches?
In which case try creating a one touch rotation.
Or disable zooming on the scrollview and implement zooming/scaling via pinch gesture recognizer.
see:
http://www.icodeblog.com/2010/10/14/working-with-uigesturerecognizers/
Could you not set scrollEnabled(NO) on your UIScrollView?
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
If the value of this property is YES , scrolling is enabled, and if it
is NO , scrolling is disabled. The default is YES.
When scrolling is disabled, the scroll view does not accept touch
events; it forwards them up the responder chain.
Things like zoomToRect:animated: don't say anything about being disabled by this flag; I'd assume that would keep working when you pan/zoom/scroll in response to your gesture events.
I think you can differentiate zoom in/zoom out and scrolling functionality by identify number of tap option on UIScrolView. Here i do same things as you want. you may try it.
- (void)viewDidLoad {
[super viewDidLoad];
imgview=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"2.png"]];
view1=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 300, 400)];
view1.backgroundColor=[UIColor greenColor];
[view1 addSubview:imgview];
objscrollview.contentMode=UIViewContentModeScaleToFill;
objscrollview.contentSize=CGSizeMake(300, 400);
objscrollview.minimumZoomScale=1;
objscrollview.maximumZoomScale=10;
[objscrollview addSubview:view1];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap)];
singleFingerTap.numberOfTapsRequired = 1;
[objscrollview addGestureRecognizer:singleFingerTap];
[singleFingerTap release];
}
//Single tap on scrollview call below method
-(void)handleSingleTap
{
NSLog(#"Singletap identify");
}
//While perform zoom in/zoom out action on scroll view it's delegate method call
//In this method, we are return view that want to zoom in/Zoom out..
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView1
{
NSLog(#"hi++++++++++++++++++");
return imgview;
}

Interrupting a scrolling/animating UIScrollView with a UIGestureRecognizer

I have a UIScrollView and a UITapGestureRecognizerwhich are both pretty basic, and have got them to work together in every way I need except one. The UIScrollView doesn't use any zooming, and the UITapGestureRecognizer just writes to the console for now.
I can get the UITapGestureRecognizer to write to the console when the UIScrollView is tapped, either while stationary or animating through setContentOffset, but I cannot get it to work when the UIScrollView is moving due to being swiped. When the UIScrollView is swiped and still in motion, the first tap after swiping will stop it moving, and then only the second tap is picked up by the UITapGestureRecognizer. I hope to get the first tap to both stop the UIScrollView from scrolling and also write to the console through the UITapGestureRecognizer.
I hope that my problem here is just through a gap in my knowledge of either the UIScrollView or UITapGestureRecognizer and there is just a Property to set to fix this, but so far no amount of reading has helped me with this issue. Any ideas on whether this is possible?
Edit: Thanks for the suggestions, please see below
Apologies, I don't think I explained myself very well. I realise the first movement on the stationary UIScrollView is a swipe (which in my case is just handled by the UIScrollView btw, not a gesture recognizer).
The problem is after swiping and releasing, if you tap while it is still in motion (and no other touch is in progress), it isn't picked up by the UITapGestureRecognizer, instead it is only picked up by the UIScrollView and stops the UIScrollView moving. If you let it decelerate then tap, this works fine. Also if it is moving due to an animation but not a swipe, the tap also works fine.
This is the same when using a `UILongPressGestureRecognizer' which is what I want to use ideally, but thought if I can't get it to work with a tap, I have no chance with that!
Sounds like you need to implement the
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
delegate method for your UITapGestureRecognizer and return YES for the UIGestureRecognizers you want to interpret tap gestures in sync with.
e.x.
// Somewhere in your code...
UIGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
tap.delegate = self;
[self.view addGestureRecognizer:tap];
[tap release];
// And the delegate method...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
n.b. You may want to be more discriminating in deciding which UIGestureRecognizer(s) you wish to work in sync with. The example will work with every other gesture recognizer.
The problem is that when the user taps the first time to scroll the UIScrollView, this is not a tap, it is a swipe. It would be considered a tap only when the user taps and releases the finger almost at the same position (without dragging the finger through the screen).
What you could do to solve your problem is: use the UIScrollView delegate method scrollViewWillBeginDragging and then you would know when the user just tapped and will start dragging the scrollview, and also add the UITapGestureRecognizer for those real taps.

Why does touchesBegan stop working when UIImageView in placed inside a UIScrollView?

UIView -> UIImageView
I know I have things somewhat working ok since I can tap on my UIImageView and see an NSLog() statement in my touchesBegan method.
.
UIView -> UIScrollView -> UIImageView
I drag that same UIImageView into a UIScrollView and touchesBegan no longer gets called when I tap on my UIImageView. (I haven't changed anything else. All the same connections, methods, and code remains unchanged.)
Why does touchesBegan no longer work? And what can I do to get it working again?
Add uitapgesture to get event
Code is
UITapGestureRecognizer *ges11=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(Handeltap:)];
[imagename addGestureRecognizer:ges11];
Create one action name "Handeltap" U will get called there.
by default UIImageView don't handle user gestures.
set UIImageView instance's userInteractionEnabled to YES
Have a look at the documentation for UIScrollView.
Because a scroll view has no scroll bars, it must know whether a touch signals an intent to scroll versus an intent to track a subview in the content. To make this determination, it temporarily intercepts a touch-down event by starting a timer and, before the timer fires, seeing if the touching finger makes any movement. If the timer fires without a significant change in position, the scroll view sends tracking events to the touched subview of the content view. If the user then drags their finger far enough before the timer elapses, the scroll view cancels any tracking in the subview and performs the scrolling itself. Subclasses can override the touchesShouldBegin:withEvent:inContentView:, pagingEnabled, and touchesShouldCancelInContentView: methods (which are called by the scroll view) to affect how the scroll view handles scrolling gestures.
I'd also recommend reading the Scroll View Programming Guide.

gesture recognizer for whole UIView

I want to find a way to animate a whole UIView which contains some ui components within it. Here's my code snippet:
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotatePiece:)];
[piece addGestureRecognizer:rotationGesture];
[rotationGesture release];
the "piece" is a uiview here which I want to rotate and it works perfectly fine. But when I add some other UI components (like UIbutton) inside it (piece view), gestures are not recognized properly when user touches on those UI components. Essentially, I want the parent to listen to the gestures even when user touches the child object.
Any ideas?
you just need to addGestureRecognizer to your subviews you add to your view. As in the rotate piece method you might be rotating your original view only,so it will work fine.
You can add a transparent UIView to cover the whole area and add the gesture recognizer there.