UIBezierPath 绘制 iOS Swift 的性能更好?

Posted

技术标签:

【中文标题】UIBezierPath 绘制 iOS Swift 的性能更好?【英文标题】:Better performance of UIBezierPath drawing iOS Swift ? 【发布时间】:2016-01-14 00:21:11 【问题描述】:

在我的应用程序中,我正在做一些绘图,但我这样做的方式非常低效,并且更新视图需要很长时间。我只是好奇有更好的方法来实现这一点。图片和代码如下。

非常感谢任何形式的帮助。

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)

【问题讨论】:

你在哪里调用drawDialWithCurrentValue?你会多次调用它吗?如果是这样,您如何从先前的调用中删除旧的形状层? 是的,这是从 func panGesture(gesture:UIPanGestureRecognizer) 调用的问题之一,我试图通过检查速度来减少调用次数 我不会为每一行添加一个图层。画出来就好了。 问题是创建了许多层let shapeLayerLine = CAShapeLayer() 尝试只使用一个层,并为该层描边/填充路径/子路径。 【参考方案1】:

你可以只用两层来做到这一点。一个用于线段,一个用于背景圆(具有不同的笔划颜色)。

此函数将为所有线段(用于您的顶层)创建一个 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 度)。

【讨论】:

以上是关于UIBezierPath 绘制 iOS Swift 的性能更好?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:贝塞尔曲线(UIBezierPath)-----Swift

如何在 iOS Swift4 中创建这个圆形?

使用UIBezierPath在Swift中绘制椭圆

iOS 图形绘制(二)-UIBezierPath

iOS - 如何在使用自定义 UIBezierPath 绘制的 CAShapeLayer 中设置 CATextLayer?

添加 Line 方法后 Swift Uibezierpath 没有响应