UIAnimator 的 UISnapBehavior 可能与 UIScrollview 一起使用吗? [英] UIAnimator's UISnapBehavior possible with UIScrollview?
问题描述
我想弄清楚是否可以在 UIScrollview 内使用 UIAnimator 的 UISnapBehavior 来使滚动视图的内容对齐到一个点.到目前为止,我的研究结果表明这是不可能的.
我正在努力实现的目标
UIScrollView 在用户拖动滚动视图时对齐"到某个点.但是,滚动必须从对齐位置恢复,而用户不必抬起触摸.
Apple 似乎在其 iOS 照片应用程序的照片编辑中实现了这一点.(见下方截图)
我的尝试
我试图通过将 UIPanGestureRecognizer 附加到滚动视图并使用它的速度来获得这种行为.如果用户正在向吸附点拖动,滚动视图将禁用滚动,动画到吸附点,完成动画后将重新启用滚动.
然而,这会导致用户必须在拖动后抬起触摸并重新拖动滚动视图的问题.然而,苹果似乎在没有解除阻力的情况下做到了.
我尝试模仿 iOS 照片应用.这是我的逻辑:
//计算捕捉点的内容偏移量让 snapPoint = CGPoint(x: 367, y: 0)//更改这些值以进行测试让 minDistanceToSnap = 7.0让 minVelocityToSnap = 25.0让 minDragDistanceToReleaseSnap = 7.0让 snapDuringDecelerating = false
这种滚动需要3个阶段
enum SnapState {案例将捕捉案例 didSnap案件将发布}
willSnap:
默认状态.决定何时捕捉.比较contentOffset 与 SnapPoint 的距离与 minDistanceToSnap
和scrollview 速度与 minVelocityToSnap
.更改为didSnap
状态.didSnap:
手动setContentOffset
到提供的contextOffset(snapPoint)
.在scrollView
上计算dragDistance
.如果用户拖动超过一定距离 (minDragDistanceToReleaseSnap
) 更改为willRelease
状态.willRelease:
如果距离snapPoint的滚动距离
大于minDistanceToSnap
,则再次更改为willSnap
状态.立>
extension ViewController: UIScrollViewDelegate {func scrollViewDidScroll(scrollView: UIScrollView) {开关(快照状态){案例.willSnap:让 distanceFromSnapPoint = distance( between: scrollView.contentOffset, and: snapPoint)让速度 = scrollView.panGestureRecognizer.velocityInView(view)让速度距离 = 距离(之间:速度,和:CGPointZero)if distanceFromSnapPoint <= minDistanceToSnap &&速度距离 <= minVelocityToSnap &&(snapDuringDecelerating || velocityDistance > 0.0) {startSnapLocaion = scrollView.panGestureRecognizer.locationInView(scrollView)snapState = .didSnap}案例.didSnap:scrollView.setContentOffset(快照点,动画:假)变量拖动距离 = 0.0让位置 = scrollView.panGestureRecognizer.locationInView(scrollView)dragDistance = distance( between: location, and: startSnapLocaion)如果拖动距离 >minDragDistanceToReleaseSnap {startSnapLocaion = CGPointZerosnapState = .willRelease}案例.willRelease:让 distanceFromSnapPoint = distance( between: scrollView.contentOffset, and: snapPoint)如果 distanceFromSnapPoint >minDistanceToSnap {snapState = .willSnap}}}}
辅助函数
func distance(point1: CGPoint, and point2: CGPoint) ->双倍的 {return Double(hypotf(Float(point1.x - point2.x), Float(point1.y - point2.y)))}
在 Github 上做了一个演示项目:https://github.com/rishi420/SnapDrag>
注意:项目是用 Xcode 7.2 制作的.您可能需要稍作更改才能编译.
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:
// CALCULATE A CONTENT OFFSET FOR SNAPPING POINT
let snapPoint = CGPoint(x: 367, y: 0)
// CHANGE THESE VALUES TO TEST
let minDistanceToSnap = 7.0
let minVelocityToSnap = 25.0
let minDragDistanceToReleaseSnap = 7.0
let snapDuringDecelerating = false
This kind of scrolling needs 3 stages
enum SnapState {
case willSnap
case didSnap
case willRelease
}
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
.
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
switch(snapState) {
case .willSnap:
let distanceFromSnapPoint = distance(between: scrollView.contentOffset, and: snapPoint)
let velocity = scrollView.panGestureRecognizer.velocityInView(view)
let velocityDistance = distance(between: velocity, and: CGPointZero)
if distanceFromSnapPoint <= minDistanceToSnap && velocityDistance <= minVelocityToSnap && (snapDuringDecelerating || velocityDistance > 0.0) {
startSnapLocaion = scrollView.panGestureRecognizer.locationInView(scrollView)
snapState = .didSnap
}
case .didSnap:
scrollView.setContentOffset(snapPoint, animated: false)
var dragDistance = 0.0
let location = scrollView.panGestureRecognizer.locationInView(scrollView)
dragDistance = distance(between: location, and: startSnapLocaion)
if dragDistance > minDragDistanceToReleaseSnap {
startSnapLocaion = CGPointZero
snapState = .willRelease
}
case .willRelease:
let distanceFromSnapPoint = distance(between: scrollView.contentOffset, and: snapPoint)
if distanceFromSnapPoint > minDistanceToSnap {
snapState = .willSnap
}
}
}
}
Helper function
func distance(between point1: CGPoint, and point2: CGPoint) -> Double {
return Double(hypotf(Float(point1.x - point2.x), Float(point1.y - point2.y)))
}
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.
这篇关于UIAnimator 的 UISnapBehavior 可能与 UIScrollview 一起使用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!