Swift代码实现:获取UIPanGestureRecognizer拖动视图的位移值
解决UIPanGestureRecognizer结束时位移值始终为0的问题
我来帮你搞定这个问题~你之所以在gestureRecognizer.state == .ended时打印的位移是(x:0, y:0),核心原因是你在.changed状态的处理中,每次都调用了gestureRecognizer.setTranslation(.zero, in: self.view),这个操作会把当前手势的位移值直接清零,等到拖动结束时,手势的位移已经被重置为0了,自然拿不到真实的总位移。
下面给你两种可行的解决方案:
方案一:手动记录总位移
在你的类中添加一个属性来累加每次拖动的位移,这样就能在结束时拿到完整的总位移:
步骤1:添加记录总位移的属性
在你的ViewController类里(或者对应的视图类)添加一个私有属性:
private var totalTranslation = CGPoint.zero
步骤2:修改手势处理方法
更新handlePan方法,在不同状态下处理总位移的记录和使用:
@objc fileprivate func handlePan(_ gestureRecognizer : UIPanGestureRecognizer){ // 先安全解包被拖动的视图 guard let draggedView = gestureRecognizer.view else { return } switch gestureRecognizer.state { case .began: // 开始拖动时重置总位移 totalTranslation = .zero makeDisappearButtons() deletebox.isHidden = false case .changed: let currentTranslation = gestureRecognizer.translation(in: self.view) // 累加本次位移到总位移中 totalTranslation.x += currentTranslation.x totalTranslation.y += currentTranslation.y // 更新被拖动视图的位置 draggedView.center = CGPoint(x: draggedView.center.x + currentTranslation.x, y: draggedView.center.y + currentTranslation.y) // 依旧重置当前手势的位移(不影响我们记录的总位移) gestureRecognizer.setTranslation(.zero, in: self.view) // 原有交互动画逻辑保留 if draggedView.frame.intersects(deletebox.frame) { UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: { draggedView.transform = .init(scaleX: 0.6, y: 0.6) self.deletebox.transform = .init(scaleX: 1.2, y: 1.2) }, completion: nil) } else { UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: { self.deletebox.transform = .identity draggedView.transform = .identity }, completion: nil) } case .ended: makeButtonsReAppear() // 原有删除/复位逻辑保留 if draggedView.frame.intersects(deletebox.frame) { draggedView.isHidden = true draggedView.removeFromSuperview() } else { draggedView.transform = .identity } // 这里打印我们手动记录的总位移 print("拖动总位移:x:\(totalTranslation.x), y:\(totalTranslation.y)") deletebox.isHidden = true default: break } }
方案二:通过视图初始位置计算位移
另一种思路是在拖动开始时记录视图的初始位置,结束时用当前位置减去初始位置得到总位移:
步骤1:添加记录初始位置的属性
private var initialViewCenter: CGPoint?
步骤2:修改手势处理方法
在.began时记录初始位置,.ended时计算位移:
@objc fileprivate func handlePan(_ gestureRecognizer : UIPanGestureRecognizer){ guard let draggedView = gestureRecognizer.view else { return } switch gestureRecognizer.state { case .began: // 记录视图的初始中心位置 initialViewCenter = draggedView.center makeDisappearButtons() deletebox.isHidden = false case .changed: // 原有拖动逻辑不变 let currentTranslation = gestureRecognizer.translation(in: self.view) draggedView.center = CGPoint(x: draggedView.center.x + currentTranslation.x, y: draggedView.center.y + currentTranslation.y) gestureRecognizer.setTranslation(.zero, in: self.view) // 原有交互动画逻辑保留 if draggedView.frame.intersects(deletebox.frame) { UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: { draggedView.transform = .init(scaleX: 0.6, y: 0.6) self.deletebox.transform = .init(scaleX: 1.2, y: 1.2) }, completion: nil) } else { UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: { self.deletebox.transform = .identity draggedView.transform = .identity }, completion: nil) } case .ended: makeButtonsReAppear() // 原有删除/复位逻辑保留 if draggedView.frame.intersects(deletebox.frame) { draggedView.isHidden = true draggedView.removeFromSuperview() } else { draggedView.transform = .identity } // 计算总位移 if let initialCenter = initialViewCenter { let totalTranslation = CGPoint(x: draggedView.center.x - initialCenter.x, y: draggedView.center.y - initialCenter.y) print("拖动总位移:x:\(totalTranslation.x), y:\(totalTranslation.y)") } deletebox.isHidden = true default: break } }
两种方案都能解决你的问题,你可以根据自己的习惯选择~
内容的提问来源于stack exchange,提问作者StackGU
相关产品推荐
相关产品推荐

