如何在视图坐标空间间像转换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
相关产品推荐
相关产品推荐

