创建圆形动画的正确方法是什么?

Joh*_*Doe 1 animation drawing core-graphics ios swift

我刚看到这个图像,对我来说很有趣,如何在Swift中创建这种类型的动画:

在此输入图像描述

所以,我有很多灰色的圆圈,当我设置角度时,例如45度,它会将这些灰色的牙齿填充到0..45度内的蓝色.

您可以向我解释正确的方法,或者您可以显示不同的片段(这会很棒).后来我会搜索或阅读它.

提前致谢!

Ham*_*ish 5

如果你只需要个别"齿"的改变,而不是使用牙齿作为掩模,对实心填充颜色,你可以使用核芯显卡,而不是核心动画(尽管核心动画一般是首选).所以为了做到这一点,我们应该做以下事情:

  1. UIView要插入我们的绘图代码的子类
  2. 创建一个包含的路径对象数组 UIBezierPath
  3. 设置计时器以更新进度值和 setNeedsDisplay
  4. drawRect:,绘制路径并根据进度为每个路径分配填充

首先,让我们定义我们将在这个UIView子类中使用的变量.

class TeethLoaderView : UIView {

    let numberOfTeeth = UInt(60) // Number of teeth to render
    let teethSize = CGSize(width:8, height:45) // The size of each individual tooth
    let animationDuration = NSTimeInterval(5.0) // The duration of the animation

    let highlightColor = UIColor(red: 29.0/255.0, green: 175.0/255.0, blue: 255.0/255.0, alpha: 1) // The color of a tooth when it's 'highlighted'
    let inactiveColor = UIColor(red: 233.0/255.0, green: 235.0/255.0, blue: 236.0/255.0, alpha: 1) // The color of a tooth when it isn't 'hightlighted'

    var progress = NSTimeInterval(0.0) // The progress of the loader
    var paths = [UIBezierPath]() // The array containing the UIBezier paths
    var displayLink = CADisplayLink() // The display link to update the progress
    var teethHighlighted = UInt(0) // Number of teeth highlighted

    ...
Run Code Online (Sandbox Code Playgroud)

现在让我们添加一个函数来创建我们的路径.

func getPaths(size:CGSize, teethCount:UInt, teethSize:CGSize, radius:CGFloat) -> [UIBezierPath] {

    let halfHeight = size.height*0.5;
    let halfWidth = size.width*0.5;
    let deltaAngle = CGFloat(2*M_PI)/CGFloat(teethCount); // The change in angle between paths

    // Create the template path of a single shape.
    let p = CGPathCreateWithRect(CGRectMake(-teethSize.width*0.5, radius, teethSize.width, teethSize.height), nil);

    var pathArray = [UIBezierPath]()
    for i in 0..<teethCount { // Copy, translate and rotate shapes around

        let translate = CGAffineTransformMakeTranslation(halfWidth, halfHeight);
        var rotate = CGAffineTransformRotate(translate, deltaAngle*CGFloat(i))
        let pathCopy = CGPathCreateCopyByTransformingPath(p, &rotate)!

        pathArray.append(UIBezierPath(CGPath: pathCopy)) // Populate the array
    }

    return pathArray
}
Run Code Online (Sandbox Code Playgroud)

这很简单.我们只需为单个"牙齿"创建一条路径,然后将此路径复制到我们需要的牙齿数量,为每个牙齿平移和旋转路径.

接下来我们要设置我们的视图.我要去一个CADisplayLink计时器,以便动画在所有设备上以相同的速度运行.

override init(frame: CGRect) {
    super.init(frame: frame)
    commonSetup()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonSetup()
}

private func commonSetup() {
    self.backgroundColor = UIColor.whiteColor()
    paths = getPaths(frame.size, teethCount: numberOfTeeth, teethSize: teethSize, radius: ((frame.width*0.5)-teethSize.height))

    displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDidFire));
    displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们只设置背景颜色,以及设置我们的计时器并初始化我们将要使用的路径.接下来我们要设置一个函数来在CADisplayLink触发时更改视图的进度.

func displayLinkDidFire() {

    progress += displayLink.duration/animationDuration

    if (progress > 1) {
        progress -= 1
    }

    let t = teethHighlighted

    teethHighlighted = UInt(round(progress*NSTimeInterval(numberOfTeeth))) // Calculate the number of teeth to highlight

    if (t != teethHighlighted) { // Only call setNeedsDisplay if the teethHighlighted changed
        setNeedsDisplay()
    }
}
Run Code Online (Sandbox Code Playgroud)

这里没有什么复杂的,我们只是更新进度,teethHighlighted并调用setNeedsDisplay()重绘视图,如果teethHighlighted更改.

最后,我们想绘制视图.

override func drawRect(rect: CGRect) {

    let ctx = UIGraphicsGetCurrentContext()

    CGContextScaleCTM(ctx, -1, -1) // Flip the context to the correct orientation
    CGContextTranslateCTM(ctx, -rect.size.width, -rect.size.height)

    for (index, path) in paths.enumerate() { // Draw each 'tooth'

        CGContextAddPath(ctx, path.CGPath);

        let fillColor = (UInt(index) <= teethHighlighted) ? highlightColor:inactiveColor;

        CGContextSetFillColorWithColor(ctx, fillColor.CGColor)
        CGContextFillPath(ctx)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想沿着Core Animation路径前进,我将此代码调整为Core Animation层


最后结果

在此输入图像描述


完整项目:https://github.com/hamishknight/Circle-Loader