You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:02:28