在Core Graphics中创建一个包含多个彩色线段的​​圆圈

时间:2016-02-14 04:49:30

标签: ios swift core-graphics uibezierpath

我正在尝试绘制一个饼图,它将由相同大小的片段组成,每个片段都有不同的颜色。我的代码基于此SO: Draw a circular segment progress in SWIFT

let circlePath = UIBezierPath(ovalInRect: CGRect(x: 200, y: 200, width: 150, height: 150))
var segments: [CAShapeLayer] = []
let segmentAngle: CGFloat = 1.0 / CGFloat(totalSegments)

for var i = 0; i < totalSegments; i++ {
    let circleLayer = CAShapeLayer()
    circleLayer.path = circlePath.CGPath

    // start angle is number of segments * the segment angle
    circleLayer.strokeStart = segmentAngle * CGFloat(i)

    //create a gap to show segments
    let gapSize: CGFloat = 0.008
    circleLayer.strokeEnd = circleLayer.strokeStart + segmentAngle - gapSize

    circleLayer.lineWidth = 10
    circleLayer.strokeColor = UIColor(red:0,  green:0.004,  blue:0.549, alpha:1).CGColor
    circleLayer.fillColor = UIColor.redColor().CGColor

    // add the segment to the segments array and to the view
    segments.insert(circleLayer, atIndex: i)
    view.layer.addSublayer(segments[i])
}

但是使用它我想做到这一点,所以我可以根据for循环中的索引值i为每个段着色。最初我只是用奇数或偶数进行测试,但发现填充部分会用最后使用的颜色填充整个圆圈。

我怀疑这是因为填充颜色填充整个圆圈,即使描边有一个有限的开始和结束。我怎样才能创建相同的效果,但为每个片段启用单独的填充颜色?

1 个答案:

答案 0 :(得分:6)

这是一个饼图绘制功能,我在操场上玩得很开心。也许您可以根据自己的要求使用它:

 import Foundation
 import UIKit


 // Pie Chart Drawing function
 // --------------------------
 // - Takes an array of tuples with relative value and color for slices
 // - draws at center coordinates with a givn radius
 //
 func drawPieChart(slices:[(value:CGFloat, color:UIColor)], at center:CGPoint, radius:CGFloat)
 {  
     // the calue component of the tuples are summed up to get the denominator for surface ratios
     let totalValues:CGFloat = slices.reduce(0, combine: {$0 + $1.value})

     // starting at noon (-90deg)
     var angle:CGFloat = -CGFloat(M_PI)/2

     // draw each slice going counter clockwise
     for (value,color) in slices
     {
        let path = UIBezierPath()

        // slice's angle is proportional to circumference 2π 
        let sliceAngle = CGFloat(M_PI)*2*value/totalValues 
        // select fill color from tuple  
        color.setFill()

        // draw pie slice using arc from center and closing path back to center
        path.moveToPoint(center)
        path.addArcWithCenter( center, 
                       radius: radius, 
                   startAngle: angle, 
                     endAngle: angle - sliceAngle, 
                    clockwise: false
                             )
        path.moveToPoint(center)
        path.closePath()

        // draw slice in current context
        path.fill()

        // offset angle for next slice
        angle -= sliceAngle
     }
 }

 // Pie chart Data
 let slices:[(value:CGFloat, color:UIColor)] =
   [ (3, UIColor.greenColor()),
     (5, UIColor.redColor()),
     (8, UIColor.blueColor()),
     (13,UIColor.yellowColor())
   ]  

 // UIView
 let viewSize    = CGSize(width: 300, height: 300)
 let view:UIView = UIView(frame: CGRect(origin: CGPointZero, size: viewSize))
 view.backgroundColor = UIColor.whiteColor()

 // CoreGraphics drawing
 UIGraphicsBeginImageContextWithOptions(viewSize, false, 0)

 // draw pie chart in Image context
 drawPieChart(slices, at:CGPointMake(150,150), radius:100 )

 // set image to view layer (you could also use it elsewhere)
 view.layer.contents = UIGraphicsGetImageFromCurrentImageContext().CGImage
 UIGraphicsEndImageContext()

 // Playground (quick look or Timeline)
 let preview = view

注意:要获得相同大小的段,只需在元组数组的所有条目中提供相同的值。

更新

这是函数的变体,它只绘制饼图的周长(边缘):

 func drawPieRim(_ slices:[(value:CGFloat, color:UIColor)], at center:CGPoint, 
                     radius:CGFloat, thickness:CGFloat=30)
 {  
     let totalValues:CGFloat = slices.reduce(0){$0 + $1.value}
     let gapAngle      =  CGFloat(Double.pi) * 0.01
     var angle:CGFloat =  -CGFloat(Double.pi)/2
     for (value,color) in slices
     {
        let path       = UIBezierPath()
        let sliceAngle = CGFloat(Double.pi)*2*value/totalValues
        path.lineWidth = thickness
        color.setStroke()
        path.addArc( withCenter:center, 
                       radius: radius, 
                   startAngle: angle + sliceAngle - gapAngle, 
                     endAngle: angle, 
                    clockwise: false)
        path.stroke()
        angle += sliceAngle 
     }
 }