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

如何为容器视图配置双向UIPanGestureRecognizer实现左右滑动旋转

实现容器视图双向滑动旋转功能

现状与需求

  • 已为容器视图添加UIPanGestureRecognizer,可实现向右滑动旋转(锚点(x: 1, y: 1)),运行正常,现有响应代码如下:
@objc func respondToPanGesture(recognizer: UIPanGestureRecognizer) {
    
    container.setAnchorPoint(anchorPoint: .init(x: 1, y: 1))
    
    let touchLocation = recognizer.location(in: container.superview)
    let center = container.center
    
    switch recognizer.state {
    case .began :
        self.deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(container.transform.b, container.transform.a)
        
    case .changed:
        backgroundView.backgroundColor = UIColor.systemGreen
        let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
        let angleDiff = self.deltaAngle - angle
        
        if angleDiff <= 0, angleDiff > -5, angleDiff > -0.50 {
            container.transform = CGAffineTransform(rotationAngle: -angleDiff)
        }
        
    case .ended:
        UIView.animate(withDuration: 0.6, animations: { [weak self] in
            guard let this = self else { return }
            this.container.transform = CGAffineTransform(rotationAngle: 0)
        }, completion: { [weak self] _ in
            guard let this = self else { return }
            this.container.setAnchorPoint(anchorPoint: .init(x: 0.5, y: 0.5))
        })
        
    default: break
    }
}
  • 需要新增向左滑动旋转效果,对应锚点为(x: 0, y: 1),但添加新的UIPanGestureRecognizer后,视图仅生效最后添加的手势,需实现双向滑动逻辑。

解决方案:复用单个手势实现双向滑动

无需添加多个手势,在同一个手势响应方法中,根据触摸起始位置判断滑动方向,动态切换锚点和旋转逻辑:

修改后的完整代码

// 新增枚举标记滑动方向
enum PanDirection {
    case left
    case right
}

private var currentDirection: PanDirection?
private var deltaAngle: CGFloat = 0

@objc func respondToPanGesture(recognizer: UIPanGestureRecognizer) {
    let touchLocation = recognizer.location(in: container.superview)
    let center = container.center
    
    switch recognizer.state {
    case .began:
        // 根据触摸位置与容器中心的水平偏移判断方向
        let isRightSwipe = touchLocation.x > center.x
        currentDirection = isRightSwipe ? .right : .left
        
        // 设置对应锚点
        let anchorPoint = isRightSwipe ? CGPoint(x: 1, y: 1) : CGPoint(x: 0, y: 1)
        container.setAnchorPoint(anchorPoint: anchorPoint)
        
        // 计算初始角度差
        deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(container.transform.b, container.transform.a)
        
    case .changed:
        backgroundView.backgroundColor = UIColor.systemGreen
        guard let direction = currentDirection else { return }
        
        let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
        var angleDiff = deltaAngle - angle
        
        // 根据方向调整角度计算逻辑
        if direction == .left {
            // 左滑时反转角度差的符号,确保旋转方向正确
            angleDiff = angle - deltaAngle
            // 限制左滑的角度范围(可根据需求调整)
            if angleDiff >= 0, angleDiff < 5, angleDiff < 0.50 {
                container.transform = CGAffineTransform(rotationAngle: angleDiff)
            }
        } else {
            // 右滑保留原有逻辑
            if angleDiff <= 0, angleDiff > -5, angleDiff > -0.50 {
                container.transform = CGAffineTransform(rotationAngle: -angleDiff)
            }
        }
        
    case .ended, .cancelled:
        // 动画恢复初始状态
        UIView.animate(withDuration: 0.6, animations: { [weak self] in
            guard let this = self else { return }
            this.container.transform = CGAffineTransform(rotationAngle: 0)
        }, completion: { [weak self] _ in
            guard let this = self else { return }
            this.container.setAnchorPoint(anchorPoint: .init(x: 0.5, y: 0.5))
            this.currentDirection = nil
        })
        
    default: break
    }
}

关键说明

  1. 方向判断:在.began状态时,通过触摸位置与容器中心的x坐标比较,确定是左滑还是右滑
  2. 动态锚点:根据滑动方向设置对应锚点,右滑用(1,1),左滑用(0,1)
  3. 角度适配:左滑时反转角度差的符号,保证旋转方向符合预期,同时保留角度范围限制
  4. 状态重置:手势结束或取消时,统一恢复容器的transform和锚点,并清空当前方向标记

内容的提问来源于stack exchange,提问作者martin wotterman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:30:56