以与CGRect、CGPoint等类似的方式转换UIBezierPath

问题描述 投票:0回答:1

UIView
具有在坐标空间之间转换点、矩形等的功能。我需要为
UIBezierPaths
做同样的事情。作为说明,考虑两个视图,
viewA
viewB
。我们在
rectA : CGRect
的坐标空间中有
viewA
。我们可以计算一下:

let rectB = viewB.convert(rectA, from:viewA)

现在假设我们从矩形创建一条路径:

let pathA = UIBezierPath(rect: rectA)

问题是,如何计算

rectB
。我们可以简单地:

let pathB = UIBezierPath(rect: rectB)

但只有当我们有

rectB
时,这才有效。如果我们只有“pathA”怎么办?

我认为要做到这一点,我们需要进行转换

aTob
。然后我们可以做:

var pathB = pathA
pathB.apply(aTob)

所以问题归结为如何计算

aTob
。为简单起见,假设没有旋转。

根据结果,在

pathA
中绘制
viewA
应在屏幕上绘制与在
pathB
中绘制
viewB
相同形状和位置的路径。

swift uiview uibezierpath cgaffinetransform
1个回答
1
投票

一种解决方案是使用平移变换在贝塞尔路径上调用

apply()

您可以通过将

viewB
的原点转换为
viewA
的坐标空间来计算变换所需的x和y。

这里有一些示例代码,您可以将其放入 Swift Playground:

// Some setup
let rectA = CGRect(x: 40, y: 60, width: 200, height: 100)
let rectB = CGRect(x: 10, y: 80, width: 200, height: 100)
let viewA = UIView(frame: rectA)
let viewB = UIView(frame: rectB)
// Create pathA
let pathA = UIBezierPath(rect: rectA)

// Calculate the offset needed to move from viewA to viewB
let offset = viewA.convert(CGPoint.zero, from: viewB)
let tranform = CGAffineTransform(translationX: offset.x, y: offset.y)
// Copy pathA
let pathB = UIBezierPath()
pathB.append(pathA)
// Shift pathB
pathB.apply(tranform)
// Check result
print(pathA)
print(pathB)

输出:

<UIBezierPath: 0x600002c31e80; <MoveTo {40, 60}>,
 <LineTo {140, 60}>,
 <LineTo {140, 160}>,
 <LineTo {40, 160}>,
 <Close>
<UIBezierPath: 0x600002c12280; <MoveTo {10, 80}>,
 <LineTo {110, 80}>,
 <LineTo {110, 180}>,
 <LineTo {10, 180}>,
 <Close>

我相信这就是您正在寻找的。

offset
的计算可能会倒退。如果
pathB
的结果方向错误,请将
offset
行更改为:

let offset = viewB.convert(CGPoint.zero, from: viewA)

这是

UIView
的扩展,用于将
UIBezierPath
从一个视图转换为另一个视图/从另一个视图转换:

extension UIView {
    private func adjust(_ path: UIBezierPath, by offset: CGPoint) -> UIBezierPath {
        let transform = CGAffineTransform(translationX: offset.x, y: offset.y)
        let result = UIBezierPath()
        result.append(path)
        result.apply(tranform)

        return result
    }

    func convert(_ path: UIBezierPath, from view: UIView) -> UIBezierPath {
        let offset = convert(CGPoint.zero, from: view)

        return adjust(path, by: offset)
    }

    func convert(_ path: UIBezierPath, to view: UIView) -> UIBezierPath {
        let offset = convert(CGPoint.zero, to: view)

        return adjust(path, by: offset)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.