iOS Swift - 填充弧线的动画,而不是边框​​描边

时间:2017-06-08 20:01:15

标签: ios swift core-animation geometry

我正在尝试从特定的起始角度到某个结束角度实施弧形绘制。我试图动画绘制弧形但没有运气。

我已经找了几个实现但是所有这些实现都指的是绘制动画的圆圈。

喜欢用一种颜色绘制一个馅饼。具有一定的起始和结束角度。饼图的动画。

我喜欢的是在从开始角度到结束角度动画弧形的同时进行动画填充。

正如顺时针绘制弧线一样,绘制时正在填充内部颜色。

任何想法如何在Swift中实现这一点?

提前致谢。

修改

这就是我所画的:

(灰色显示绘图饼图所覆盖的区域)

enter image description here

绘制Pie的代码

import Foundation
import UIKit

@IBDesignable class PieChart : UIView {

    @IBInspectable var percentage: CGFloat = 50 {
        didSet {
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var outerBorderWidth: CGFloat = 2 {
        didSet {
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var outerBorderColor: UIColor = UIColor.white {
        didSet {
            self.setNeedsDisplay()
        }
    }

    @IBInspectable var percentageFilledColor: UIColor = UIColor.primary {
        didSet {
            self.setNeedsDisplay()
        }
    }

    let circleLayer = CAShapeLayer()

    override func draw(_ rect: CGRect) {
        drawPie(rect: rect, endPercent: percentage, color: UIColor.primary)
    }

    func drawPie(rect: CGRect, endPercent: CGFloat = 70, color: UIColor) {
        let center = CGPoint(x: rect.origin.x + rect.width / 2, y: rect.origin.y + rect.height / 2)
        let radius = min(rect.width, rect.height) / 2

        let gpath = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: CGFloat(360.degreesToRadians), clockwise: true)
        UIColor.white.setFill()
        gpath.fill()

        let circlePath = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(0), endAngle:CGFloat(360.degreesToRadians), clockwise: true)

        circleLayer.path = circlePath.cgPath

        circleLayer.fillColor = UIColor.clear.cgColor
        circleLayer.strokeColor = outerBorderColor.cgColor
        circleLayer.lineWidth = outerBorderWidth
        circleLayer.borderColor = outerBorderColor.cgColor

        self.layer.addSublayer(circleLayer)

        let π: CGFloat = 3.14

        let halfPi: CGFloat = π / 2

        let startPercent: CGFloat = 0.0

        let startAngle = (startPercent / 100 * π  * 2 - π ) + halfPi
        let endAngle = (endPercent / 100 * π  * 2 - π ) + halfPi

        let path = UIBezierPath()
        path.move(to: center)
        path.addArc(withCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
        path.close()
        percentageFilledColor.setFill()
        path.fill()
    }
}

1 个答案:

答案 0 :(得分:0)

我已经使用playground和swift创建了这段代码。此代码将绘制一个饼图,为填充颜色设置动画。确保在Xcode上打开时间轴窗格以查看动画是否正常工作。我无法找到将路径功能直接传递给CAAnimation的方法,因此我的解决方法是创建一个步骤列表,每个步骤包含一个百分比阶段的路径。您可以更改动画动画的步骤。

//: Playground - noun: a place where people can play

import UIKit
import XCPlayground

let STEPS_ANIMATION = 50

let initialPercentage : CGFloat = 0.10
let finalPercentage : CGFloat = 0.75


func buildPiePath(frame : CGRect, percentage : CGFloat) -> UIBezierPath {

    let newPath = UIBezierPath()

    let startPoint = CGPoint(x: frame.size.width, y: frame.height / 2.0)
    let centerPoint = CGPoint(x: frame.size.width / 2.0, y: frame.height / 2.0)
    let startAngle : CGFloat = 0
    let endAngle : CGFloat = percentage * 2 * CGFloat(M_PI)

    newPath.move(to: centerPoint)
    newPath.addLine(to: startPoint)
    newPath.addArc(withCenter: centerPoint,
                   radius: frame.size.width / 2.0,
                   startAngle: startAngle,
                   endAngle: endAngle,
                   clockwise: true)
    newPath.addLine(to: centerPoint)
    newPath.close()
    return newPath
}

func buildPiePathList(frame: CGRect,
                      startPercentage: CGFloat,
                      finalPercentage: CGFloat) -> [AnyObject] {

    var listValues = [AnyObject]()

    for index in 1...STEPS_ANIMATION {

        let delta = finalPercentage - startPercentage
        let currentPercentage = CGFloat(index) / CGFloat(STEPS_ANIMATION)

        let percentage =  CGFloat(startPercentage + (delta * currentPercentage))
        listValues.append(buildPiePath(frame: frame,
                                       percentage: percentage)
            .cgPath)

    }

    return listValues
}




// Container for pie chart

let container = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
container.backgroundColor = UIColor.gray
XCPShowView(identifier: "Container View", view: container)

let circleFrame = CGRect(x: 20, y: 20, width: 360, height: 360)



// Red background
let background = CAShapeLayer()
background.frame = circleFrame
background.fillColor = UIColor.red.cgColor
background.path = buildPiePath(frame: circleFrame, percentage: 1.0).cgPath

container.layer.addSublayer(background)




// Green foreground that animates
let foreground = CAShapeLayer()
foreground.frame = circleFrame
foreground.fillColor = UIColor.green.cgColor
foreground.path = buildPiePath(frame: circleFrame, percentage: initialPercentage).cgPath

container.layer.addSublayer(foreground)




// Filling animation
let fillAnimation = CAKeyframeAnimation(keyPath: "path")
fillAnimation.values = buildPiePathList(frame: circleFrame,
                                        startPercentage: initialPercentage,
                                        finalPercentage: finalPercentage)
fillAnimation.duration = 3
fillAnimation.calculationMode = kCAAnimationDiscrete
foreground.add(fillAnimation, forKey:nil)