Detect Single Tap in UIScrollView

If you’ve ever been using a UIScrollView and had a need to detect a single tap, 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

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

From here we can create a new class that includes a AppScrollView object:

Class Interface Using AppScrollView

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

As with everything else, it’s easy once you know the trick.


  1. 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?


    • 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.


  2. 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?

  3. 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:

    • 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.

  4. Brilliant. Thank you for sharing. I had been playing around with a much less graceful solution!

  5. 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.

  6. 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).

  7. 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.

  8. This tutorial is excellent! Save my days of works bouncing on the wall. Thanks.

  9. 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???

  10. scrollView.userInteractionEnabled = YES; // put in the .m of your “SomeClass”

    is the one thing I noticed was missing that DevSlashNull pointed out. thanks!

  11. after 2 days of frustration, endless subclassing(subclassed UIView, UIImageView) I finally stumbled upon this article.
    You Rock.

  12. This does not work for me. I’m trying to get touch events on the UIScrollView’s super view. No events are being given to touchesEnded:withEvent:

  13. Hey All,

    Great Discussion! I’m really glad John started it. I had the same problem.

    It seems I found a good method and example code from Apple. Check out “ScrollViewSuite.” The “1_TapToZoom” project shows you a super easy way to get at tap events stollen by the scrollview. I was able to get my plain-old view controller to implement this functionality with 4-5 lines of code and no subclassing!

  14. This worked perfectly for me with a slight modification, but thank you for the great tutorial nonetheless :)

  15. thanks a million! I’ve used it grateful in test file. Though, I’m still trying to figure out why it don’t work on the tab bar application…

  16. I like your tutorial, Very simple and you focus on core messages.

    Good Job!!

  17. many thanks UIScrollView dont eat my single click any more, nice work!!!

  18. any way to update the scrollview’s current offset in the super view?

    i have a map with a rectangular slider that indicates the current position of the scrollview on the screen. i could update the position in the super view’s gameloop if i could get the position somehow. everything i’ve tried only updates the slider after any touch is finished.


  19. You are mighty. After few hours of frustration and futile efforts I finally found this article. Well done, guys!

  20. hi,
    thanx for the info but I found its not working for sdk 5 any thoughts?

    With my best,

  21. Anyone else having problems with iOS5 / Xcode 4.2, you can fix it by adding the following to your UIScrollView subclass:

    – (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.nextResponder touchesBegan: touches withEvent:event];

    iOS5 / Xcode 4.2 seems to need to register the touchesBegan before it will allow touchesEnded to exist.

    So your full UIScrollView subclass .m will contain the following:

    – (id)initWithFrame:(CGRect)frame {
    return [super initWithFrame:frame];

    // This fixes it for iOS 5 / Xcode 4.2
    – (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.nextResponder touchesBegan:touches withEvent:event];

    – (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!self.dragging){
    [self.nextResponder touchesEnded:touches withEvent:event];
    [super touchesEnded:touches withEvent:event];

    • thank you Ed Rackham, i fixed touch event in iOS5.
      now It works!

    • Thank you very much!

      I couldn’t believe that just a rebuild with Xcode 4.2 messed up this. This is a reasonable explanation. And now it works!

  22. Thanks a lot. iOS5 is getting my crazy with this kind of stuff.

    It is the fifth problem I have to solve because of iOS 5. At least it has a razonable explanation.

    Just to make any one know, because I didn’t find any explication.
    I had an object which I need to change width and X position bounds. When I set new bounds, it changes X to -0. Crazy! I solved it setting bounds twice, first time for new X position, and second time for new Width.

    First Code:
    > bounds.size.width = bounds.size.width + 40;
    > bounds.origin.x = ((bounds.size.width) * index;
    > pagingScrollView.bounds = bounds;

    Solution code:
    > bounds.size.width = bounds.size.width + 40;
    > pagingScrollView.bounds = bounds;
    > bounds.origin.x = ((bounds.size.width) * index;
    > pagingScrollView.bounds = bounds;

    I hope it can help.

  23. Thank you!!! ^^

    I solved a problem.

    But I must find long time the reason that did’nt operation.

    I don’t know how change class identity. ^^;

    • Can you please provide a little more information, I’m not sure what you mean by changing class identity?

      • In someClass’s identity inspector. I had change superclass, UIScrollView => AppScrollView in custom class. Is Wrong???? ^^;;;

Comments are closed.