如何缩放和居中 UIBezierPath?

How to Scale and Center UIBezierPath?

我正在使用 BezierPath,可以成功地在视图中制作基本的星形,效果很好。但是,视图的大小可以更改。当视图大小改变时,我无法将这条贝塞尔路径居中,我设法缩放它,但居中对我来说很难。

private func pointFrom(_ angle: CGFloat, radius: CGFloat, offset: CGPoint) -> CGPoint {
    return CGPoint(x: radius * cos(angle) + offset.x, y: radius * sin(angle) + offset.y)//CGPointMake(radius * cos(angle) + offset.x, radius * sin(angle) + offset.y)
}

private func generateStar(width:CGFloat, height:CGFloat, radius:CGFloat) -> CAShapeLayer{
    let path = UIBezierPath()
    var scale = width / height
    if width > height{
        scale = height / width
    }

    let starExtrusion:CGFloat = 60.0

    let center = CGPoint(x: width / 2.0, y: height / 2.0)

    let pointsOnStar = 5

    var angle:CGFloat = -CGFloat(.pi / 2.0)
    let angleIncrement = CGFloat(.pi * 2.0 / Double(pointsOnStar))
    let radius = width / 2.0

    var firstPoint = true

    for _ in 1...pointsOnStar {

        let point = pointFrom(angle, radius: radius, offset: center)
        let nextPoint = pointFrom(angle + angleIncrement, radius: radius, offset: center)
        let midPoint = pointFrom(angle + angleIncrement / 2.0, radius: starExtrusion, offset: center)

        if firstPoint {
            firstPoint = false
            path.move(to: point)
        }

        path.addLine(to: midPoint)//addLineToPoint(midPoint)
        path.addLine(to: nextPoint)//addLineToPoint(nextPoint)

        angle += angleIncrement
    }
    path.apply(CGAffineTransform(scaleX: scale, y: scale))
    path.close()

    let maskLayer = CAShapeLayer()
    maskLayer.path = path.cgPath

    return maskLayer
}

我怎样才能做到这一点?谢谢!

UIView 的 layoutSubviews 在调整大小时被调用,您可以通过覆盖该方法来重置遮罩。

您的路径中心使用此命令移动:

path.apply(CGAffineTransform(scaleX: scale, y: scale))

为了让你的 center 保持在中心,将它缩放 1 / scale 这样当它被缩放 scale 时,它最终会在视图的中心(因为(1 / scale) * scale == 1):

变化:

let center = CGPoint(x: width / 2.0, y: height / 2.0)

至:

let center = CGPoint(x: width / 2.0 / scale, y: height / 2.0 / scale)

这两个缩放比例相互抵消,然后路径的中心在最初计算的位置结束。


就是说,height != width 时您正在缩小星标。如果您忘记缩放并仅选择 widthheight 中的最小值作为 radius 计算,您可能会得到更好的结果:

去掉scale,或者设置为1.0,然后

变化:

let radius = width / 2.0

至:

let radius = min(width, height) / 2.0

这将使星星尽可能大,同时仍完全适合视图。


如您所见,随着恒星变小,它会变得 "fat"(更圆)。这是因为对于 starExtrusion,您有一个硬编码常量 60.0。该值应基于 radius.

计算后设置starExtrusionradius:

let radius = min(width, height) / 2.0
let starExtrusion = radius * 0.4

您可以改变 0.4 乘数来改变星星的形状。