19
votes

I currently am using a UIScrollView to work as a way of scrolling/ dragging the cursor/ marker of a graph that I am displaying on my app. I use scrollViewDidScroll, etc. to detect the contentoffset's position and manipulate what I display on the screen based on this position.

My question is if it is possible to also detect a user's single tap on the screen and get this tap's position (to then set the contentoffset to this position)?

I have read some tutorials that describe creating a subclass of a uiscrollview, but it seems like these subclasses will ONLY account for a single tap and not drags/scrolls also.

Does anyone have any insight on how I might be able to detect a user's single tap on my UIScrollView while still having its scrolling/ dragging capabilities?
Thank you in advance!

4
General practice for UIScrollViews is to not mess with the ways the user interacts with them. Apple created them as they are for a reason--you want different behavior, create your own view. Aside from that, though, I'm not really clear on the reason you want to detect the tap. The user would tap inside the scrollview, and you say you would then set the contentOffset to the tap position, but the contentOffset describes the top left corner of the content that's viewable inside the scrollview, so... What exactly do you mean?WendiKidd
yes because the contentoffset is how I determine where the scrollview "is" on the screen. In other words, the contentoffset is like a marker for how far down the scrollview the user is. So, I change the text of a label based on the position of the scrollview aka the contentoffset. So, I want a user's tap to set/update the contentoffset based on where the user tapped on the scrollviewNathan Fraenkel

4 Answers

33
votes

Use the following code for your scrollView object :

UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
singleTapGestureRecognizer.enabled = YES;
singleTapGestureRecognizer.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:singleTapGestureRecognizer];
//[singleTapGestureRecognizer release]; Not needed in ARC-enabled Project

}

- (void)singleTap:(UITapGestureRecognizer *)gesture {  
//handle taps   
}
6
votes

Swift 5

let scrollViewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(scrollViewTapped(_:)))
scrollViewTapGestureRecognizer.numberOfTapsRequired = 1
scrollViewTapGestureRecognizer.isEnabled = true
scrollViewTapGestureRecognizer.cancelsTouchesInView = false
scrollView.addGestureRecognizer(scrollViewTapGestureRecognizer)

@objc func scrollViewTapped(_ sender: UITapGestureRecognizer) {
    print("UIScrollView was tapped.")
}
1
votes

The first part of the question is pretty simple to get going. If you have a UIScrollView subclass, you can just add a touchesEnded override that looks like this:

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];

    if ([touch tapCount] == 1) {

        CGPoint location = [touch locationInView:self];

        [self setContentOffset:location animated:YES];

    }


}

In the case of the scroll view, the -locationInView for the touch will actually already have the ContentOffset added into it. What this code will do is scroll the scroll view so that the point the user touched is at the top-left of the view. This probably isn't what you want exactly, so you'll have to do things like add in an offset if you want the scroll to end up 10 pixels in, or you'd make another CGPoint with only the x value out of the location if your scroller isn't left-to-right.

This won't interfere with being able to actually do the scroll.

0
votes

Have you looked into attaching UITapGestureRecognizer to the scrollView? I've attached a UITapGestureRecognizer to a UIScrollView and used –gestureRecognizerShouldBegin: and/or –gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: to cancel the built in panning when a touch is desired.