iOS Swift - 动画绘制圆弧填充,而不是边框​​描边

标签 ios swift core-animation geometry

我正在尝试实现从某个起始角度到某个结束角度的圆弧绘制。我正在尝试绘制弧线动画,但没有运气。

我已经寻找了几个实现,但它们都指的是绘制圆的动画边框。

就像画一个馅饼,但只有一种颜色。具有一定的起始角度和终止角度。饼图的动画绘制。

我喜欢的是在弧从起始角度到结束角度进行动画处理时进行动画填充。

就像圆弧是按顺时针方向绘制的,并且在绘制时填充其内部颜色。

知道如何在 Swift 中实现这一点吗?

提前致谢。

编辑

这是我画的:

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

enter image description here

绘制饼图的代码

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()
    }
}

最佳答案

我使用 Playground 和 Swift 创建了这段代码。此代码将绘制一个饼图,并以动画方式填充颜色。确保您已在 Xcode 上打开“时间轴” Pane 以查看动画的工作情况。我找不到将路径函数直接传递给 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)

关于iOS Swift - 动画绘制圆弧填充,而不是边框​​描边,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44444580/

相关文章:

ios - 在 CAGradientLayer 上方显示 SCNScene

iphone - 为 UIImageView 的 CABasicAnimation 强制顺时针/逆时针旋转

ios - XCode Swift 自动完成在构建后崩溃

ios - rx-swift 中的 repeat-while 运算符

iphone - objective-c 源 locationManager 在自己的类中

ios - swift4 : Callback URL not approved for this client application

arrays - Swift 数组中的 CGFloat

objective-c - 视网膜显示器的矩形尺寸是多少?

ios - 以编程方式显示和隐藏容器 UIView 及其 subview

ios - UIView transitionWithView : animation behaviour with background color