我正尝试在循环中绘制如下图所示的仪表刻度。
我遵循了以下步骤:
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))
}
产生:
显然,调整 angle
、innerRadius
和 outerRadius
以适合您的目的,但这说明了一种更简单的方法来呈现所有这些勾号标记。
如果评论,您似乎反对上述方法,并有效地询问是否可以保存 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
显然,这是一种非常低效的方法(特别是因为如果您希望最近添加的内容包含在快照中,您必须使用 afterScreenUpdates
值 true
)。/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/