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

CAShapeLayer缩放异常:二次捏合手势未基于上次缩放后尺寸执行

解决CAShapeLayer二次捏合缩放回到初始尺寸的问题

这个坑我之前踩过!问题出在你每次处理捏合手势时,都是基于图层的初始变换状态来计算缩放,而没有保存上一次缩放后的最终状态。

核心原因

UIPinchGestureRecognizer的scale属性在每次手势开始时都会重置为1.0。如果你的代码每次都直接用gesture.scale去生成新的transform(比如CATransform3DMakeScale(gesture.scale, gesture.scale, 1)),那第二次手势触发时,就会从图层的初始尺寸重新计算,而不是基于第一次缩放后的结果叠加。

解决步骤

  1. 保存当前缩放状态:添加一个实例变量来记录图层的当前缩放比例,这样每次手势都能基于这个值计算新的缩放。
  2. 分阶段处理手势状态:在手势开始时记录当前缩放,手势变化时叠加缩放比例,手势结束时更新保存的状态并重置手势的scale。

完整代码示例

import UIKit

class ViewController: UIViewController {
    // 直接持有CAShapeLayer的引用,避免每次取sublayers[0]的风险
    private var shapeLayer: CAShapeLayer!
    // 记录当前的缩放比例
    private var currentScale: CGFloat = 1.0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化你的CAShapeLayer
        shapeLayer = CAShapeLayer()
        let path = UIBezierPath(rect: CGRect(x: 50, y: 50, width: 200, height: 200))
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = UIColor.blue.cgColor
        view.layer.addSublayer(shapeLayer)
        
        // 添加捏合手势
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture(_:)))
        view.addGestureRecognizer(pinchGesture)
    }
    
    @objc private func handlePinchGesture(_ gesture: UIPinchGestureRecognizer) {
        guard let layer = shapeLayer else { return }
        
        switch gesture.state {
        case .began:
            // 手势开始时,从图层的transform中提取当前缩放比例
            // m11是x轴缩放系数,m22是y轴,等比缩放时两者相等
            currentScale = layer.transform.m11
        case .changed:
            // 基于当前缩放比例,叠加手势的scale计算新的缩放
            let newScale = currentScale * gesture.scale
            // 更新图层的transform
            layer.transform = CATransform3DMakeScale(newScale, newScale, 1.0)
        case .ended, .cancelled:
            // 手势结束后,更新保存的缩放比例
            currentScale = layer.transform.m11
            // 重置手势的scale为1.0,避免影响下一次手势
            gesture.scale = 1.0
        default:
            break
        }
    }
}

额外注意事项

  • 尽量直接持有CAShapeLayer的引用,不要依赖sublayers![0]——如果后续添加其他子图层,这个索引可能会失效,还会有数组越界的风险。
  • 如果需要支持不等比缩放,需要分别保存x轴和y轴的缩放比例(比如currentScaleX和currentScaleY),在计算时分别叠加。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:50:58