更好的 UIBezierPath 绘图性能 iOS Swift ?
Better performance of UIBezierPath drawing iOS Swift ?
在我的应用程序中,我正在做一些绘图,但我这样做的方式非常低效,而且更新视图需要很长时间。我只是好奇有没有更好的方法来实现这一目标。图片和代码如下。
非常感谢任何形式的帮助。
func drawDialWithCurrentValue( currentValue:CGFloat, andNewValue newValue:CGFloat)
{
let radius = 500.0
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 0,y: radius),
radius: CGFloat(radius),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.blueColor().CGColor
shapeLayer.strokeColor = UIColor.blueColor().CGColor
shapeLayer.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayer)
let x0 = 0.0
let y0 = radius
var x1 = x0
var y1 = y0
var degsInRadians = 0.0
for var index = 0; index < 360; index++
{
if index%2 == 0
{
degsInRadians = Double(index) * (M_PI/180)
x1 = x0 + radius * cos(degsInRadians)
y1 = y0 + radius * sin(degsInRadians)
let linePath = UIBezierPath()
linePath.moveToPoint(CGPoint( x: x1, y: y1))
linePath.addLineToPoint(CGPoint( x:0, y:radius))
let shapeLayerLine = CAShapeLayer()
shapeLayerLine.path = linePath.CGPath
shapeLayerLine.fillColor = UIColor.clearColor().CGColor
shapeLayerLine.strokeColor = UIColor.greenColor().CGColor
shapeLayerLine.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayerLine)
}
}
let innerCirc = UIBezierPath(arcCenter: CGPoint(x: 0,y: radius),
radius: CGFloat(radius - 100),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer2 = CAShapeLayer()
shapeLayer2.path = innerCirc.CGPath
shapeLayer2.fillColor = UIColor.blueColor().CGColor
shapeLayer2.strokeColor = UIColor.blueColor().CGColor
shapeLayer2.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayer2)
}
你只用两层就可以做到这一点。一个用于线段,一个用于背景圆(具有不同的描边颜色)。
此函数将为所有线段(对于您的顶层)创建一个 BezierPath。如果您不打算在每次绘制时进行缩放,则应将路径的单个副本设置为静态(或实例)变量并重新使用它。即使你确实调整了形状的大小,你也应该只在半径实际改变时才重新计算路径。
func clockSegments(count:Int, radius:CGFloat, length:CGFloat)->UIBezierPath
{
let allSegments = UIBezierPath()
let baseSegment = UIBezierPath()
// baseSegment is horizontal movement from origin, followed by line up to radius
// (0,0).....................---------
baseSegment.moveToPoint( CGPointMake(radius-length, 0.0) )
baseSegment.addLineToPoint( CGPointMake(radius, 0.0) )
baseSegment.lineWidth = 3
// rotate and add segments
let segmentAngle = 2 * CGFloat(M_PI) / CGFloat(count)
let rotate = CGAffineTransformMakeRotation(segmentAngle)
for _ in 1...count
{
allSegments.appendPath(baseSegment)
baseSegment.applyTransform(rotate)
}
return allSegments
}
要获取您在示例中使用的参数的段路径,您可以这样调用该函数:
layer.path = clockSegments(360, radius:500, length:100)
在 iPad3 上,使用 SpriteKit,渲染在 200 个片段处阻塞,但如果我使用两个形状节点,每个节点有 180 个,则没有问题。这可能暗示了 BezierPath 中元素数量的实际限制。如果您遇到这个问题,您可以添加一个参数来偏移起始段并使用两个 180 段层(一个旋转 1 度)。
在我的应用程序中,我正在做一些绘图,但我这样做的方式非常低效,而且更新视图需要很长时间。我只是好奇有没有更好的方法来实现这一目标。图片和代码如下。
非常感谢任何形式的帮助。
func drawDialWithCurrentValue( currentValue:CGFloat, andNewValue newValue:CGFloat)
{
let radius = 500.0
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 0,y: radius),
radius: CGFloat(radius),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.blueColor().CGColor
shapeLayer.strokeColor = UIColor.blueColor().CGColor
shapeLayer.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayer)
let x0 = 0.0
let y0 = radius
var x1 = x0
var y1 = y0
var degsInRadians = 0.0
for var index = 0; index < 360; index++
{
if index%2 == 0
{
degsInRadians = Double(index) * (M_PI/180)
x1 = x0 + radius * cos(degsInRadians)
y1 = y0 + radius * sin(degsInRadians)
let linePath = UIBezierPath()
linePath.moveToPoint(CGPoint( x: x1, y: y1))
linePath.addLineToPoint(CGPoint( x:0, y:radius))
let shapeLayerLine = CAShapeLayer()
shapeLayerLine.path = linePath.CGPath
shapeLayerLine.fillColor = UIColor.clearColor().CGColor
shapeLayerLine.strokeColor = UIColor.greenColor().CGColor
shapeLayerLine.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayerLine)
}
}
let innerCirc = UIBezierPath(arcCenter: CGPoint(x: 0,y: radius),
radius: CGFloat(radius - 100),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer2 = CAShapeLayer()
shapeLayer2.path = innerCirc.CGPath
shapeLayer2.fillColor = UIColor.blueColor().CGColor
shapeLayer2.strokeColor = UIColor.blueColor().CGColor
shapeLayer2.lineWidth = 3.0
drawView.layer.addSublayer(shapeLayer2)
}
你只用两层就可以做到这一点。一个用于线段,一个用于背景圆(具有不同的描边颜色)。
此函数将为所有线段(对于您的顶层)创建一个 BezierPath。如果您不打算在每次绘制时进行缩放,则应将路径的单个副本设置为静态(或实例)变量并重新使用它。即使你确实调整了形状的大小,你也应该只在半径实际改变时才重新计算路径。
func clockSegments(count:Int, radius:CGFloat, length:CGFloat)->UIBezierPath
{
let allSegments = UIBezierPath()
let baseSegment = UIBezierPath()
// baseSegment is horizontal movement from origin, followed by line up to radius
// (0,0).....................---------
baseSegment.moveToPoint( CGPointMake(radius-length, 0.0) )
baseSegment.addLineToPoint( CGPointMake(radius, 0.0) )
baseSegment.lineWidth = 3
// rotate and add segments
let segmentAngle = 2 * CGFloat(M_PI) / CGFloat(count)
let rotate = CGAffineTransformMakeRotation(segmentAngle)
for _ in 1...count
{
allSegments.appendPath(baseSegment)
baseSegment.applyTransform(rotate)
}
return allSegments
}
要获取您在示例中使用的参数的段路径,您可以这样调用该函数:
layer.path = clockSegments(360, radius:500, length:100)
在 iPad3 上,使用 SpriteKit,渲染在 200 个片段处阻塞,但如果我使用两个形状节点,每个节点有 180 个,则没有问题。这可能暗示了 BezierPath 中元素数量的实际限制。如果您遇到这个问题,您可以添加一个参数来偏移起始段并使用两个 180 段层(一个旋转 1 度)。