ios - 在 Swift 4 循环中保存和重绘

标签 ios swift uibezierpath cgaffinetransform

我正尝试在循环中绘制如下图所示的仪表刻度。

Gauge Ticks

我遵循了以下步骤:

1. create a CAShapeLayer and CALayer
2. for loop 
3. draw center top line with UIBezier
4. rotate the layer in the loop
5. add CAShapeLayer to the CALayer with .addSubLayer
5. end loop

代码

let angle = CGFloat(Double.pi / 180 * 10)

turnLayer.frame            = self.bounds
self.layer.addSublayer(turnLayer)
let strokeColor            = UIColor.black.cgColor
thickLayer.frame           = frame
thickLayer.strokeColor     = strokeColor
thickLayer.fillColor       = UIColor.clear.cgColor
thickLayer.lineWidth       = 8.0


for idx in -10...10 {
    var p: CGPoint = CGPoint.init(x: bounds.width/2, y: bounds.height/8)
    let path = UIBezierPath()
    path.move(to: p)
    p = CGPoint.init(x: bounds.width/2, y: bounds.height/8 + 32)
    path.addLine(to: p)
    thickLayer.path = path.cgPath
    thickLayer.setAffineTransform(CGAffineTransform(rotationAngle: angle * CGFloat(idx)))
    turnLayer.addSublayer(thickLayer)

}

问题

我不知道如何保存和重绘中心顶线

最佳答案

与其添加一堆旋转图层,不如使用单个 CAShapeLayer 为所有刻度添加笔划,例如,

let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 3
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.lightGray.cgColor
view.layer.addSublayer(shapeLayer)

let maxRadius = min(view.bounds.width, view.bounds.height) / 2
let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

let path = UIBezierPath()

for i in 0 ... 16 {
    let angle = -(CGFloat.pi / 2.0) + CGFloat.pi / 2.0 * (CGFloat(i - 8)) / 9.0
    let outerRadius = maxRadius
    let innerRadius = maxRadius - (i % 2 == 0 ? 20 : 10)
    path.move(to: point(angle: angle, from: center, radius: outerRadius))
    path.addLine(to: point(angle: angle, from: center, radius: innerRadius))
}

shapeLayer.path = path.cgPath

在哪里

func point(angle: CGFloat, from center: CGPoint, radius: CGFloat) -> CGPoint {
    return CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle))
}

产生:

enter image description here

显然,调整 angleinnerRadiusouterRadius 以适合您的目的,但这说明了一种更简单的方法来呈现所有这些勾号标记。


如果评论,您似乎反对上述方法,并有效地询问是否可以保存 View 的快照(大概这样您以后可以在 ImageView 中显示该图像)。是的,它是:

extension UIView {
    func snapshot(afterScreenUpdates: Bool = false) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0)
        drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return image
    }
}

所以,接着你的问题“我可以添加 shapelayer 并保存快照”,答案是肯定的,你可以

let shapeLayer = ...
view.layer.addSublayer(shapeLayer)
let image = view.snapshot(afterScreenUpdates: true)

然后,如果你想使用那个快照,你必须删除 CAShapeLayer 然后在一些 ImageView 中显示快照:

shapeLayer.removeFromSuperlayer()
imageView.image = image

显然,这是一种非常低效的方法(特别是因为如果您希望最近添加的内容包含在快照中,您必须使用 afterScreenUpdatestrue)。/p>

如果您真的想高效地创建所有刻度的图像,您可能只需将 UIBezierPath 直接描边 到图像上下文即可。您只需要知道要创建的 UIImage 的大小:

func tickImage(size: CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(size, false, 0)

    let path = UIBezierPath()
    path.lineWidth = 3

    let maxRadius = size.width / 2
    let center = CGPoint(x: size.width / 2, y: size.height)

    for i in 0 ... 16 {
        let angle = -(CGFloat.pi / 2.0) + CGFloat.pi / 2.0 * (CGFloat(i - 8)) / 9.0
        let outerRadius = maxRadius
        let innerRadius = maxRadius - (i % 2 == 0 ? 20 : 10)
        path.move(to: point(angle: angle, from: center, radius: outerRadius))
        path.addLine(to: point(angle: angle, from: center, radius: innerRadius))
    }

    UIColor.lightGray.setStroke()
    path.stroke()

    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return image
}

话虽如此,我不确定您为什么要这样做而不是在这个答案的开头使用 CAShapeLayer 。如果我需要保存/上传此快照以供日后使用,我只会执行此“创建 UIImage”方法。否则 CAShapeLayer 是一个很好的方法。

关于ios - 在 Swift 4 循环中保存和重绘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45701762/

相关文章:

iphone 方向问题..

ios - Swift:从抛出初始化器调用可失败初始化器?

ios - UITableViewCell Storyboard 注册依赖于初始 View Controller ?

objective-c - 如何调整和翻译 CAShapeLayer?

ios - 生成用于设置 Apple 推送通知的 .pem 文件

ios - swift 4 : Could not load NIB in bundle: 'NSBundle' for custom UITableViewCell (no IB)

ios - 在 Swift 中每次动画迭代后延迟

ios - 如何将相机胶卷中的所有照片和视频插入阵列?

objective-c - UIBezierPath 相交

ios - 在 iOS 中创建六边形 ImageView 形状