通过按钮平滑地动画圆形进度圈

时间:2017-03-13 18:57:36

标签: ios swift animation cabasicanimation

我在进步圈中遇到奇怪的视觉怪癖。我希望绿色圆圈(CAShapeLayer)能够以五分之一的增量平滑地进行动画制作。 0/5 =没有绿色圆圈。 5/5 =全绿色圆圈。问题是绿色圆圈在它应该的地方动画过去,然后突然收缩到适当的位置。按下加号和减号按钮时会发生这种情况。下面有一个gif演示正在发生的事情。

每个动画的持续时间应该持续0.25秒,并且应该平滑动画显示UP和DOWN(取决于是否按下加号或减号按钮)从动画最后结束的位置(目前不是发生的情况。)

在我的UIView中,我绘制圆圈,以及制作进度位置动画的方法:

class CircleView: UIView {

    let progressCircle = CAShapeLayer()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    override func draw(_ rect: CGRect) {
        let circlePath = UIBezierPath(ovalIn: self.bounds)
        progressCircle.path = circlePath.cgPath
        progressCircle.strokeColor = UIColor.green.cgColor
        progressCircle.fillColor = UIColor.red.cgColor
        progressCircle.lineWidth = 10.0

        // Add the circle to the view.
        self.layer.addSublayer(progressCircle)
    }


    func animateCircle(circleToValue: CGFloat) {
        let fifths:CGFloat = circleToValue / 5
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = 0.25
        animation.fromValue = fifths
        animation.byValue = fifths
        animation.fillMode = kCAFillModeBoth
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        progressCircle.strokeEnd = fifths

        // Create the animation.
        progressCircle.add(animation, forKey: "strokeEnd")
    }


}

在我的VC中:

我通过以下方式启动圆圈和起点:

let myDrawnCircle = CircleView()
var startingPointForCircle = CGFloat()

viewDidAppear:

    startingPointForCircle = 0.0
    myDrawnCircle.frame = CGRect(x: 100, y: 100, width: 150, height: 150)
    myDrawnCircle.backgroundColor = UIColor.white
    myDrawnCircle.animateCircle(circleToValue: startingPointForCircle)
    self.view.addSubview(myDrawnCircle)

    textLabel.text = "\(startingPointForCircle)"

制作炫酷动画的实际按钮:

@IBAction func minusButtonPressed(_ sender: UIButton) {
    if startingPointForCircle > 0 {
        startingPointForCircle -= 1
        textLabel.text = "\(startingPointForCircle)"
        myDrawnCircle.animateCircle(circleToValue: startingPointForCircle)
    }
}
@IBAction func plusButtonPressed(_ sender: UIButton) {
    if startingPointForCircle < 5 {
        startingPointForCircle += 1
        textLabel.text = "\(startingPointForCircle)"
        myDrawnCircle.animateCircle(circleToValue: startingPointForCircle)
    }
}

这里有一个gif,向您展示动态生动的动画。

Crude / jerky animation

如何让我的动画顺利地从适当的值中设置适当的值?

2 个答案:

答案 0 :(得分:0)

我的猜测是它与使用密钥路径有关。我不知道如何使用键路径来修复它,但您可以使用自定义视图尝试不同的大头钉,并为传递给用于绘制弧的方法的值设置动画。

以下代码由PaintCode生成。为arc传递的值指定了绘制圆弧的圆上的点。这用于自定义UIView的drawRect方法。创建自定义视图的CGFloat属性,只需更改该值,然后在动画代码后调用视图上的setNeedsDisplay

func drawCircleProgress(frame frame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), arc: CGFloat = 270) {
    //// General Declarations
    let context = UIGraphicsGetCurrentContext()

    //// Color Declarations
    let white = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)
    let white50 = white.colorWithAlpha(0.5)

    //// Oval Drawing
    CGContextSaveGState(context)
    CGContextTranslateCTM(context, frame.minX + 20, frame.minY + 20)
    CGContextRotateCTM(context, -90 * CGFloat(M_PI) / 180)

    let ovalRect = CGRect(x: -19.5, y: -19.5, width: 39, height: 39)
    let ovalPath = UIBezierPath()
    ovalPath.addArcWithCenter(CGPoint(x: ovalRect.midX, y: ovalRect.midY), radius: ovalRect.width / 2, startAngle: 0 * CGFloat(M_PI)/180, endAngle: -arc * CGFloat(M_PI)/180, clockwise: true)

    white.setStroke()
    ovalPath.lineWidth = 1
    ovalPath.stroke()

    CGContextRestoreGState(context)
}

答案 1 :(得分:0)

期望的结果就像在animateCircle方法中注释掉Value / byValue一样简单。这是由@dfri指出的 - “将fromValue和toValue都设置为nil然后:”在目标层的表示层中keyPath的先前值和目标层的表示层中keyPath的当前值之间进行插值。“

//animation.fromValue = fifths
//animation.byValue = fifths