Is it possible to disable the dragging waiting time in an UIScrollView? - iphone

When the user touches into an UIScrollView and wants to scroll, there is a little delay. UIKit tries to find out if the user wanted to touch the content in the scroll view or if the user wanted to scroll. So it waits a moment if the finger moves far enough, and then starts scrolling. Could I tell it that it must start scrolling with no delay? I have a situation where the content really doesn't care at all about touches, so the UIScrollView doesn't have to wait, it can immediately start scrolling.

I think you're looking for the delaysContentTouches property on UIScrollView. Setting that to NO should cause the UIScrollView to immediately start processing touch events.

Related

UIScrollView scrollEnabled does not stop two finger gestures

The UIScrollView property scrollEnabled stops one finger gestures but multiple finger gestures seem still to work albeit with the error message
Ignoring call to [UIPanGestureRecognizer setTranslation:inView:] since
gesture recognizer is not active.
Is this bad? Am I doing something wrong? canCancelContentTouches seems to stop the action but the error message remains. Can I thus ask
should I worry about the the error message?
is canCancelContentTouches the best way to cancel all scroll actions?
what am I doing wrong?
Your question is a bit unclear, but basically scrollEnabled is only designed to stop scrolling of the scrollview itself, not interaction with content inside the scrollview.
If you want to stop people from interacting with content within the scrollview, using a UIGestureRecognizer and its delegate to intercept the gestures and ignore them seem like the way to go.

iPhone SDK - UIButton on a UIScrollView touch interactions

I have a UIScrollView which is doing some custom pinch zooming. To do this I subclassed UIScrollView, the overwrote the touch methods touchesBegan, touchesMoved, and touchesEnded. Everything works well and as expected.
My problem comes when I try to add a series of UIView subviews, I can only detect taps on my UIScrollView when the UIView UserInteractions is set to NO. I would like to be able to continue to detect two finger taps on my UIScrollView, AND a single finger tap on any of my UIView subview.
Is this possible?
I've tried countless number of ways with little help. Does anyone have any experience in this?
Cheers,
Brett
Apple's documentation for UIScrollView explains how it does it:
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.
There are a couple of methods for interception given as answers to this question: How to make a superview intercept button touch events?
Any UIView with userInteractionEnabled will block touches from reaching views under it. You may have to rethink how you are structuring your layout. Or subclass the UIView to change how it's handling touches.

UIScrollView touch handling

I'm reading the following about UIScrollView from Apple UIScrollView Class Reference Documentation:
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 don't understand the sentence starting with "If the user then drags their finger far enough before the timer elapses..." I thought the timer already fired according to the previous sentence. Is it talking about another timer in this one?
It's confusing. I believe there are 2 possible behaviors depending on whether your scrollView has the delaysContentTouches property set (and or the canCancelContentTouches property is set)
If delaysContentTouches is set:
When the user taps the scroll view 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 drags their finger far enough before the timer elapses, the scroll view begins scrolling.
If the timer has fired:
If canCancelContentTouches is set the scroll view cancels and touches passed to its subviews and begins scrolling. Otherwise, no scrolling.
If timer has not expired before the user drags his/her finger, scrolling happens.
I think I got that right... (someone might want to double-check)
HTH

UIScrollView with UIButton doesn't scroll when touch down on button

I've got a UIScrollView in my UIView. I've added some UIButtons to the scroll view.
If I touch down not on a button and drag, the scroll view drags fine.
If I touch down on a button and drag then the scroll view doesn't move.
I want the scroll view to always scroll around if dragged and the buttons only get selected on the Touch Up Inside event.
I don't want to check "Delay Content Touches" because I don't want to have to wait for the delay.
Does anyone know what I need to do to get this to work?
Regards,
Rich
Perhaps just outdated, but Redent84's answer is plain wrong.
You can solve this by adding:
scrollView.canCancelContentTouches = YES;
There's no automatic way of doing that. You have to manually handle the touch event, and then determine what the user wants to do, if he moves the finger X pixels up or down, then he wants to scroll, and if he releases the touch inside the button, then he probably wants to activate that action.
Regards!

How to filter touch events for a UIScrollView?

I have a view that displays a PDF. It should be zoomable, so I also created a UIScrollView, and in its delegate I implemented viewForZoomingInScrollView to return the PDF view. So far so good.
However, when the user reaches the edge of a zoomed PDF page, I'd like to flip to the next page. Sounds easy, yet I can't seem to figure out how to do it.
I've tried some different approaches:
Using scrollViewDidScroll to detect if scrolling has reached the edge. The problem here is that if zoomScale is 1, and therefore scrolling is not possible, then this function is never called. But the UIScrollView still swallows all touch events, so I also can't detect reaching the edge in touchesMoved. Setting canCancelContentTouches to NO when not zoomed is not an option, as that would also prevent zooming in.
Subclassing UIScrollView, and forwarding some of the touch events to the next responder. Unfortunately when UIScrollView detects a drag operation and cancels the touch, touchesMoved and touchesEnded are not called even for the UIScrollView subclass anymore. Again, setting canCancelContentTouches to NO is not good, as that would also prevent some desired UIScrollView functionality.
Creating a transparent view on top of the scroll view (as a sibling of it), so that this view gets all touch events first, and then forwarding some of the touches to the scroll view. Unfortunately the scroll view doesn't respond to these calls.
I can't use touchesShouldCancelInContentView, becasue that doesn't get the actual touches as an argument, and whether or not I want the scroll view to handle the touch event also depends on the properties of the touch event itself (eg. a touch movement in a direction in which we're already at the edge should not be cancelled by the scroll view, but a movement in the other direction could be).
Looks like whatever UIScrollView is doing is not initiated from touchesBegan / touchesMoved, but instead it gets some notifications about the touches way before that. Possibly in some undocumented way that I can't intercept, nor reproduce.
So is there any way to get notified about all touch movements done over a UIScrollView, while still being able to use (when certain conditions apply) the UIScrollView for zooming and scrolling?
Ok, so here's what I did in the end:
Leaving all scrolling and zooming up to UIScrollView, and handling page turning in the UIScrollViewDelegate's scrollViewDidEndDragging:willDecelerate: is almost a solution, except that this function is never called if the whole content is on-screen, so dragging / scrolling is not possible.
Swipes in this case are handled in a ViewController's touchesBegan / touchesEnded functions, but for this to work, we need to make sure that the UIScrollView does not cancel these events. However, in other cases the UIScrollView should be able to cancel touches so that it can do zooming and scrolling.
The UIScrollView should be able to cancel touches if:
Scrolling is possible (and needed) because the whole content doesn't fit on screen (zoomScale > 1 in my case),
OR
The user touched the screen with two fingers, so that zooming in and out works.
When scrolling is not possible, and the user single-touched the screen, then touches should not be cancelled, and touch events should be forwarded to the view controller.
So I created a UIScrollView subclass.
This subclass has a property pointing to the ViewController.
Using the touchesXXX methods I keep track of the current touch count.
I forward all touch events to the ViewController.
And finally, I've overridden touchesShouldCancelInContentView:, and return NO when zoomScale <= 1 and touchCount == 1.