swift - 动画绘制一个圆

标签 swift geometry uiviewanimation progress drawrect

我正在寻找一种动画绘制圆的方法。我已经能够创建圆圈,但它把所有的东西都画在一起了。

这是我的 CircleView 类:

import UIKit

class CircleView: UIView {
  override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()
  }

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }


  override func drawRect(rect: CGRect) {
    // Get the Graphics Context
    var context = UIGraphicsGetCurrentContext();

    // Set the circle outerline-width
    CGContextSetLineWidth(context, 5.0);

    // Set the circle outerline-colour
    UIColor.redColor().set()

    // Create Circle
    CGContextAddArc(context, (frame.size.width)/2, frame.size.height/2, (frame.size.width - 10)/2, 0.0, CGFloat(M_PI * 2.0), 1)

    // Draw
    CGContextStrokePath(context);
  }
}

下面是我如何将它添加到我的 View Controller 中的 View 层次结构中:

func addCircleView() {
    let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
    var circleWidth = CGFloat(200)
    var circleHeight = circleWidth
    // Create a new CircleView
    var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))

    view.addSubview(circleView)
}

有没有办法让画圆的动画超过 1 秒?

例如,动画的一部分看起来像这张图片中的蓝线:

partial animation

最佳答案

最简单的方法是使用核心动画的强大功能为您完成大部分工作。为此,我们必须将您的圆形绘制代码从您的 drawRect 函数移动到 CAShapeLayer。 .然后,我们可以使用 CABasicAnimationCAShapeLayerstrokeEnd 设置动画属性从 0.01.0strokeEnd 是这里魔法的重要组成部分;来自文档:

Combined with the strokeStart property, this property defines the subregion of the path to stroke. The value in this property indicates the relative point along the path at which to finish stroking while the strokeStart property defines the starting point. A value of 0.0 represents the beginning of the path while a value of 1.0 represents the end of the path. Values in between are interpreted linearly along the path length.

如果我们将 strokeEnd 设置为 0.0,它不会绘制任何东西。如果我们将它设置为 1.0,它会画一个完整的圆。如果我们将它设置为 0.5,它会绘制一个半圆。等

因此,首先,让我们在 CircleViewinit 函数中创建一个 CAShapeLayer 并将该层添加到 View 的 sublayers(还要确保删除 drawRect 函数,因为图层现在将绘制圆圈):

let circleLayer: CAShapeLayer!

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()
    
    // Use UIBezierPath as an easy way to create the CGPath for the layer.
    // The path should be the entire circle.
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(Double.pi * 2.0), clockwise: true)
    
    // Setup the CAShapeLayer with the path, colors, and line width
    circleLayer = CAShapeLayer()
    circleLayer.path = circlePath.CGPath
    circleLayer.fillColor = UIColor.clearColor().CGColor
    circleLayer.strokeColor = UIColor.redColor().CGColor
    circleLayer.lineWidth = 5.0;
    
    // Don't draw the circle initially
    circleLayer.strokeEnd = 0.0
    
    // Add the circleLayer to the view's layer's sublayers
    layer.addSublayer(circleLayer)
}

注意:我们正在设置 circleLayer.strokeEnd = 0.0 以便不会立即绘制圆。

现在,让我们添加一个函数,我们可以调用它来触发圆形动画:

func animateCircle(duration: NSTimeInterval) {
    // We want to animate the strokeEnd property of the circleLayer
    let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))

    // Set the animation duration appropriately
    animation.duration = duration

    // Animate from 0 (no circle) to 1 (full circle)
    animation.fromValue = 0
    animation.toValue = 1

    // Do a linear animation (i.e. the speed of the animation stays the same)
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)

    // Set the circleLayer's strokeEnd property to 1.0 now so that it's the
    // right value when the animation ends.
    circleLayer.strokeEnd = 1.0

    // Do the actual animation
    circleLayer.add(animation, forKey: "animateCircle")
}

然后,我们需要做的就是更改您的 addCircleView 函数,以便在您将 CircleView 添加到其 superview 时触发动画:

func addCircleView() {
    let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
     var circleWidth = CGFloat(200)
     var circleHeight = circleWidth

        // Create a new CircleView
     var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))

     view.addSubview(circleView)

     // Animate the drawing of the circle over the course of 1 second
     circleView.animateCircle(1.0)
}

所有这些放在一起应该看起来像这样:

circle animation

注意:它不会那样重复,它会在动画后保持一个完整的圆。

关于swift - 动画绘制一个圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26578023/

相关文章:

animation - 在addsubview时显示动画

swift - 如何将视频保存到应用程序的目录并在 View Controller 中播放?

swift - 如何在单元格快速删除后删除多余的空间

swift - 无法使用图像名称对 SKSpriteNode 进行子类化

c - 变量的值在循环中不改变

c++ - 我可以在 boost::geometry 的多边形内存储附加信息吗?

java - 用数字打印倒三角形 - Java

ios - 后退按钮启动 UIViewPropertyAnimator?

objective-c - iOS - 在 iPad 上为 UIView 设置动画,同时更改 x 原点和宽度?

swift - 如何创建具有可变属性的函数