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

如何在视图坐标空间间像转换CGRect一样转换UIBezierPath?

不同UIView坐标空间间转换UIBezierPath的方法

问题场景

UIView自带的convert(_:from:)方法可轻松实现矩形、点在不同坐标空间的转换,但UIBezierPath无法直接复用该逻辑。例如:

  • 已知viewA坐标空间内的矩形rectA,可通过以下代码得到viewB坐标空间中的rectB:
    let rectB = viewB.convert(rectA, from: viewA)
    
  • 基于rectA创建路径pathA:
    let pathA = UIBezierPath(rect: rectA)
    

若已知rectB,可直接通过UIBezierPath(rect: rectB)得到对应路径,但如果仅持有pathA,该如何转换得到viewB中对应的路径?

解决方案:通过仿射变换矩阵转换路径

核心思路是计算从viewA坐标空间到viewB坐标空间的仿射变换矩阵,再将矩阵应用到pathA上。以下是具体实现:

1. 直接获取坐标转换矩阵

利用CALayer的convert(_:to:)方法,可直接获取viewA的layer到viewB的layer的变换矩阵,该矩阵已包含平移、缩放(若有旋转也会自动处理):

let aToBTransform = viewA.layer.convert(CGAffineTransform.identity, to: viewB.layer)

2. 将矩阵应用到UIBezierPath

由于UIBezierPath是不可变对象,需先复制原路径再应用变换:

guard let pathB = pathA.copy() as? UIBezierPath else {
    // 处理路径复制失败的异常情况
    return
}
pathB.apply(aToBTransform)

此时pathB就是viewB坐标空间中,与viewA内pathA在屏幕上形状、位置完全一致的路径。

手动计算无旋转场景的变换矩阵(可选)

若想手动推导无旋转下的变换矩阵,可通过转换两个基准点实现:

  • 转换viewA原点到viewB坐标:
    let originInB = viewB.convert(CGPoint.zero, from: viewA)
    
  • 转换viewA单位点到viewB坐标:
    let unitPointInB = viewB.convert(CGPoint(x: 1, y: 1), from: viewA)
    
  • 计算缩放因子与平移量:
    let scaleX = unitPointInB.x - originInB.x
    let scaleY = unitPointInB.y - originInB.y
    let translateX = originInB.x
    let translateY = originInB.y
    
  • 构建变换矩阵:
    let aToBTransform = CGAffineTransform(scaleX: scaleX, y: scaleY)
        .translatedBy(x: translateX, y: translateY)
    

后续同样将矩阵应用到复制后的路径即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:12:48