Skip to content

16.2_在手势结束时计算目标位置

掌握手势结束时的位置计算 🎯

在拖拽手势(UIPanGestureRecognizer)结束时,精确计算视图的最终目标位置是实现流畅用户体验的关键。这不仅仅是简单地停止拖拽,更是为视图的“释放”动画奠定基础。想象一下,你拖动一个卡片,当手指离开屏幕时,卡片会平滑地移动到某个预设位置,而不是突然停下。这种平滑过渡的魔法就始于这里!✨

获取手势速度与当前位置 🚀

UIPanGestureRecognizer的状态变为UIGestureRecognizer.State.ended时,我们就能获取到宝贵的速度信息。你可以通过调用velocity(in:)方法来获取手势在指定视图中的速度向量。这个速度向量包含了X轴和Y轴上的分量,单位是点/秒。例如,如果速度是 (100, 50),这意味着视图在X方向上每秒移动100点,Y方向上每秒移动50点。

  • 当前视图位置: gesture.view!.center
  • 手势在父视图中的速度: gesture.velocity(in: superview)
  • 手势在视图中的位移: gesture.translation(in: view)

这些数据是计算目标位置的基石。有了它们,我们就能预测视图在惯性作用下会“飞”多远。

预测目标位置的数学原理 💡

计算目标位置的核心在于结合当前位置和手势结束时的速度。我们可以使用一个简单的物理模型:距离 = 速度 × 时间。当然,这里的时间并不是固定的,而是模拟一个减速过程。一个常用的方法是引入一个“减速因子”或“摩擦力”的概念。例如,我们可以假设视图在释放后会在0.5秒内减速到停止。

swift
let velocity = gesture.velocity(in: superview)
let currentCenter = gesture.view!.center
let decelerationRate: CGFloat = 0.998 // 模拟摩擦力
let projectionTime: CGFloat = 0.5 // 预测时间,例如0.5秒

let targetX = currentCenter.x + velocity.x * projectionTime * decelerationRate
let targetY = currentCenter.y + velocity.y * projectionTime * decelerationRate
let targetPosition = CGPoint(x: targetX, y: targetY)

这个decelerationRate非常重要,它决定了视图减速的快慢。一个接近1的数值意味着减速缓慢,视图会“飞”得更远;而一个较小的数值则会使视图更快地停下来。

边界检测与吸附效果 🚧

仅仅计算出目标位置还不够,我们还需要确保视图不会“飞出”屏幕边界。在计算出targetPosition后,你需要对其进行调整,使其始终保持在父视图的可见范围内。

  1. 获取父视图边界: superview.bounds
  2. 获取视图自身大小: gesture.view!.bounds.size
  3. 调整目标位置:
    • targetPosition.x = max(min(targetPosition.x, superview.bounds.maxX - viewHalfWidth), viewHalfWidth)
    • targetPosition.y = max(min(targetPosition.y, superview.bounds.maxY - viewHalfHeight), viewHalfHeight)

此外,你还可以实现“吸附”效果。例如,如果视图的目标位置非常接近屏幕边缘,你可以让它自动吸附到边缘。这会大大提升用户体验,让界面看起来更加智能和响应迅速。想象一下,当卡片接近屏幕边缘时,它会自动“弹”到边缘,而不是停留在中间。这就像磁铁一样吸引着它!🧲

准备动画数据 🎬

一旦你计算出了最终的targetPosition,并对其进行了边界调整,你就拥有了启动释放动画所需的所有信息。这个targetPosition将作为UIView.animate方法中的toValue,引导视图平滑地移动到最终位置。结合initialSpringVelocity参数,你可以让动画在开始时就带上之前计算出的速度,从而实现更加真实的物理效果。这就像给动画注入了生命,让它动起来更加自然!🎉

本站使用 VitePress 制作