![](/img/trans.png)
[英]Is it possible to snap UIViews using UISnapBehavior consecutively
[英]UIAnimator's UISnapBehavior possible with UIScrollview?
我试图找出是否可以在UIScrollview内使用UIAnimator中的UISnapBehavior来使滚动视图的内容对齐到一个点。 到目前为止,我的发现导致这是不可能的。
我正在努力实现的目标
当用户拖动滚动视图时,UIScrollView会“捕捉”到特定点。 然而,滚动必须从捕捉位置恢复,而用户不必抬起触摸。
苹果似乎在其iOS Photos App中通过Photo Editing实现了这一目标。 (请参见下面的屏幕截图)
我尝试过的
我试图通过将UIPanGestureRecognizer附加到滚动视图并使用其速度来获得此行为。 如果用户向着捕捉点拖动,则滚动视图将禁用滚动,以动画形式捕捉到捕捉点,完成动画后将重新启用滚动。
但是,这导致了以下问题:在拖动并重新拖动滚动视图后,用户必须抬起修饰框。 然而,苹果似乎已经做到了这一点,而无需解除阻力。
我试图模仿iOS Photos应用。 这是我的逻辑:
// 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
这种滚动需要三个阶段
enum SnapState {
case willSnap
case didSnap
case willRelease
}
willSnap:
默认状态。 确定何时捕捉。 比较contentOffset distance from SnapPoint with minDistanceToSnap
和scrollview velocity with minVelocityToSnap
。 更改为didSnap
状态。 didSnap:
手动setContentOffset
到提供contextOffset(snapPoint)
在dragDistance
上计算scrollView
。 如果用户拖动超过一定距离( minDragDistanceToReleaseSnap
), willRelease
改为willRelease
状态。 willRelease:
如果distance scroll from snapPoint
大于minDistanceToSnap
则再次更改为willSnap
状态。 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
}
}
}
}
辅助功能
func distance(between point1: CGPoint, and point2: CGPoint) -> Double {
return Double(hypotf(Float(point1.x - point2.x), Float(point1.y - point2.y)))
}
在Github上做了一个演示项目: https : //github.com/rishi420/SnapDrag
注意:使用Xcode 7.2创建的项目。 您可能需要稍作改动才能进行编译。
不要将UIPanGestureRecognizer直接添加到UIScrollView中。 而是将其添加到容器视图中,然后在选择器中手动设置UIScrollView contentOffset。
禁用UIScrollView本身的交互,或使用委托,以防止直接与滚动视图交互。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.