Detect Single Tap in UIScrollView
If you’ve ever been using a UIScrollView and had a need to detect a single tap, I hear you. In the Savini Rims and Rides iPhone application, I had a horizontal scrollview of six cars as one element of the user interface. Selecting on a car (tapping once) was to launch a video. Trouble is, UIScrollView eats the single tap I was after.
Let me show you what I came up with to catch single taps within a UIScrollView. First, I created a subclass of UIScrollView as follows:
Subclass UIScrollView
@interface AppScrollView : UIScrollView { } @end
The implementation of the AppScrollView is all of two methods, the initialization code and one method to manage touch events. The trick in detecting one touch is to look for the touchesEnded event, and within that method, check to see if the user is dragging when the event is triggered. If not dragging, pass the event up to the next responder – most likely, your class that contains an AppScrollView object.
AppScrollView Implementation
#import "AppScrollView.h" @implementation AppScrollView - (id)initWithFrame:(CGRect)frame { return [super initWithFrame:frame]; } - (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event { // If not dragging, send event to next responder if (!self.dragging) [self.nextResponder touchesEnded: touches withEvent:event]; else [super touchesEnded: touches withEvent: event]; } @end
From here we can create a new class that includes a AppScrollView object:
Class Interface Using AppScrollView
#import <UIKit/UIKit.h> @class AppScrollView; @interface SomeClass : UIViewController <UIScrollViewDelegate> { AppScrollView *scrollView; ... } @end
Now, inside the implementation of the SomeClass class, all we need to do is look for the touchesEnded event that was passed up the responder chain. For example, a skeleton of the class using AppScrollView may look as follows:
Class Implementation Receiving Single Tap
#import "AppScrollView.h" @implementation SomeClass ... - (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event { // Process the single tap here ... } ... @end
As with everything else, it’s easy once you know the trick.





















Hi, great tutorial. It is almost working for me. The method gets called but the code in my statement:
UITouch *touch = [touches anyObject];
if([touch view] == _scrollView )
{
does not get called. What view I am supposed to be detecting the touch on? Do I have to overlay a UIImageView on top of the scroll view and detect the touch on that?
Thanks
Kieran,
If I understand your question…generally you would have something inside your scroll view that you would be detecting a touch on, for example a series of images, which was the case for the project I was working on.
John
Hi John ,
Thanks for the reply. I am displaying a scrollview which displays an image. When swiped the next image appears. I am using some sample code from apple to achieve this. I have a nib which has the image view and a class connected to that nib. I then have another class which controls the scrollview.
I create an instance variable to my class controlling the images :
SlidesViewController *sVC;
and tried:
if([touch view] == sVC.imageView )
{
But that failed with EXC_BAD_ACCESS.
Without seeing all the code it’s hard to know exactly where the problem is – are you sure the variable imageView is properly tied to the instance in the nib?
Hi John,
In my SlidesViewController.h I define a UIImageView *imageView variable. This is hooked up correctly in the corresponding NIB. In my class that handles the scrollview I then have the following code:
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
// Process the single tap here
NSLog(@”Touch called”);
SlidesViewController *sVC;
//Create a UITouch object
UITouch *touch = [touches anyObject];
if(touch.view == sVC.imageView)
{
The app crashes with the error EXC_BAD_ACCESS when I attempt to single-tap and this code is run.
My code is pretty much identical to Apple page control sample code available here: http://developer.apple.com/iphone/library/samplecode/PageControl/index.html
I can see the problem for the bad access, if you look at the variable sVC, notice that you are referring to a new instance you just defined (SlidesViewController *sVC), therefore it points to nil. It looks like you need to refer to an instance variable with the name imageView.
Hi John,
Thanks for pointing that out. That has fixed the error.
Thanks,
Kieran McGrady
Brilliant. Thank you for sharing. I had been playing around with a much less graceful solution!
I have tried this, however without much success (because I am new and this may just be over my head). Is there anyone interested in posting a link to the actual code (including NIB files) as I am sure I am missing some elements when trying to implement the subview (uiscrollview still works but not seem to care about the tap I have placed using this method).
Thanks for any help you can provide…R.J.
You just made my day! Thanks, Ralf
The “Apple approved” way of doing this is to subclass the view inside the UIScrollView and make sure its userInteraction property is set to YES.
Then implement touchesEnded on the subclassed view and do the appropriate action.
UIScrollView delays sending touches to the subviews until it determines that the touches don’t constitute a scroll action. If it has already sent the touches and they turn into a scroll it will send the touchesCanceled message (this behavior can be modified with the delaysContentTouches and canCancelContentTouches properties).
Thanks again for this tutorial. I was able to get this working, however I am trying to use the touch event to change views (back to my main menu view controller, and have tried various methods however all of them have the similar result (with an warning error “AppScrollView may not respond to – presentModalViewController). (essentially my app has a main menu which opens my UIScrollView controller to show a gallery of images I want to tap to go back to the main menu). I can however open a URL so I know my subclassing and touch controls are correct. Any ideas would be greatly appreciated. Thanks.
This tutorial is excellent! Save my days of works bouncing on the wall. Thanks.
excellent tutorial !!!
thanks so much
Its a good tutorial!!!!!
I had a question I use to add a webview on subclassing scrollview and the problem is touches end is catched only after the userinteraction of webview is set NO…..
What I can do???