【问题标题】:How to Scale and Center UIBezierPath?如何缩放和居中 UIBezierPath?
【发布时间】:2019-09-07 06:47:27
【问题描述】:

我正在使用 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
}

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

【问题讨论】:

    标签: ios swift uibezierpath


    【解决方案1】:

    你的路径中心随着这个命令移动:

    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 时,你正在缩小你的星星。如果您忘记缩放比例,而只为您的radius 计算选择widthheight 中的最小值,您可能会得到更好的结果:

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

    变化:

    let radius = width / 2.0
    

    到:

    let radius = min(width, height) / 2.0
    

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


    正如您所注意到的,当它变小时,恒星会变得“胖”(更圆)。这是因为对于starExtrusion,您有一个硬编码常量60.0。该值应基于radius

    计算radius后设置starExtrusion

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

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

    【讨论】:

    • 我试过了,但没有成功,你能分享完整的代码吗,也许我做错了。
    • 我提出了两个不同的建议。您是否尝试了每一个,但都没有成功?
    • 你能分享你的完整代码吗?比如pointFrom()是什么?
    • 我更新了答案,以便更清楚地了解我所做的更改。我的两个建议都适用于您的代码。
    • 是的,你绝对是对的,问题都是关于挤压的。由于我动态计算了starExtrusion,现在它一直在工作。感谢您的最新更新。
    【解决方案2】:

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

    【讨论】:

    • 我已经调用了layoutSubviews,但问题是如何重置掩码?因为掩码只有在宽度和高度相等时才有效。
    猜你喜欢
    • 2021-11-26
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 2012-03-09
    • 2016-04-04
    • 1970-01-01
    • 2015-07-10
    相关资源
    最近更新 更多