I am trying to figure out if I can use a UISnapBehavior from UIAnimator inside a UIScrollview to make scroll view's content snap to a point. So far my findings have been lead to that this is impossible.
What I am Trying to Achieve
UIScrollView to 'snap' to certain point while the user is dragging the scroll view. However, the scrolling has to resume from snapped position without the user having to lift the touch.
Apple seems to achieve this in Photo Editing in their iOS Photos App. (See screenshot below)
What I Tried
I tried to gain this behavior by attaching a UIPanGestureRecognizer to the scrollview and using it's velocity. If the user is dragging towards the snapping point, scroll view will disable scrolling, animate to the snapping point, when done animating it will re-enable scrolling.
However, this lead to the issue where the user HAS TO LIFT the touch up after the drag and re-drag the scrollview. Yet, Apple seems to have done it without having to lift the drag.
I've tried to mimic iOS Photos app. Here is my logic:
This kind of scrolling needs 3 stages
willSnap:
Default state. Decide when to snap. ComparecontentOffset distance from SnapPoint with minDistanceToSnap
andscrollview velocity with minVelocityToSnap
. Change todidSnap
state.didSnap:
ManuallysetContentOffset
to a providedcontextOffset(snapPoint)
. CalculatedragDistance
onscrollView
. If user drag more than a certain distance (minDragDistanceToReleaseSnap
) change towillRelease
state.willRelease:
Change towillSnap
state again ifdistance scroll from snapPoint
is more thanminDistanceToSnap
.Helper function
Made a demo project on Github: https://github.com/rishi420/SnapDrag
Note: Project made with Xcode 7.2. You may need to change a bit to compile.
Don't add the UIPanGestureRecognizer directly to the UIScrollView. Rather add it to a container view, then in the selector, set the UIScrollView contentOffset manually.
Disable interaction on the UIScrollView itself, or use the delegate, to prevent interaction directly with the scroll view.