创建旋转圆圈加载动画

dev*_*r82 16 animation ios swift

我正在尝试创建一个旋转的圆形加载器动画,如下面的Android项目(https://github.com/pedant/sweet-alert-dialog).

在此输入图像描述

我不需要整个弹出对话框 - 只需要旋转部分.它会无限地改变颜色和旋转(直到我选择解除它).

我对快速有点新鲜,我从来没有做过动画.这是我到目前为止(在iOS的类似项目中找到代码):

图层设置:

    outlineLayer.position = CGPointMake(0,
        0);
    outlineLayer.path = outlineCircle
    outlineLayer.fillColor = UIColor.clearColor().CGColor;
    outlineLayer.strokeColor = UIColor(red: 150.0/255.0, green: 216.0/255.0, blue: 115.0/255.0, alpha: 1.0).CGColor;
    outlineLayer.lineCap = kCALineCapRound
    outlineLayer.lineWidth = 4;
    outlineLayer.opacity = 0.1
    self.layer.addSublayer(outlineLayer)

    circleLayer.position = CGPointMake(0,
        0);
    circleLayer.path = path
    circleLayer.fillColor = UIColor.clearColor().CGColor;
    circleLayer.strokeColor = UIColor(red: 150.0/255.0, green: 216.0/255.0, blue: 115.0/255.0, alpha: 1.0).CGColor;
    circleLayer.lineCap = kCALineCapRound
    circleLayer.lineWidth = 4;
    circleLayer.actions = [
        "strokeStart": NSNull(),
        "strokeEnd": NSNull(),
        "transform": NSNull()
    ]
    self.layer.addSublayer(circleLayer)
Run Code Online (Sandbox Code Playgroud)

动画:

let strokeStart = CABasicAnimation(keyPath: "strokeStart")
    let strokeEnd = CABasicAnimation(keyPath: "strokeEnd")
    let factor = 0.545
    let timing = CAMediaTimingFunction(controlPoints: 0.3, 0.6, 0.8, 1.2)

    strokeEnd.fromValue = 0.00
    strokeEnd.toValue = 0.93
    strokeEnd.duration = 10.0 * factor
    strokeEnd.timingFunction = timing
    strokeEnd.autoreverses = true

    strokeStart.fromValue = 0.0
    strokeStart.toValue = 0.68
    strokeStart.duration =  10.0 * factor
    strokeStart.beginTime =  CACurrentMediaTime() + 3.0 * factor
    strokeStart.fillMode = kCAFillModeBackwards
    strokeStart.timingFunction = timing
    strokeStart.repeatCount = HUGE

    circleLayer.strokeStart = 0.68
    circleLayer.strokeEnd = 0.93

    self.circleLayer.addAnimation(strokeEnd, forKey: "strokeEnd")
    self.circleLayer.addAnimation(strokeStart, forKey: "strokeStart")
Run Code Online (Sandbox Code Playgroud)

但我所拥有的并不近,我不知道从哪里开始.我正在做的是改变价值并看看它是如何影响的,但我觉得我在这里迷失了.

如何在示例中实现这样的动画?

rob*_*off 69

我没有仔细分析动画的确切参数,但这对我来说很好看:

微调视图

import UIKit

@IBDesignable
class SpinnerView : UIView {

    override var layer: CAShapeLayer {
        get {
            return super.layer as! CAShapeLayer
        }
    }

    override class var layerClass: AnyClass {
        return CAShapeLayer.self
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.fillColor = nil
        layer.strokeColor = UIColor.black.cgColor
        layer.lineWidth = 3
        setPath()
    }

    override func didMoveToWindow() {
        animate()
    }

    private func setPath() {
        layer.path = UIBezierPath(ovalIn: bounds.insetBy(dx: layer.lineWidth / 2, dy: layer.lineWidth / 2)).cgPath
    }

    struct Pose {
        let secondsSincePriorPose: CFTimeInterval
        let start: CGFloat
        let length: CGFloat
        init(_ secondsSincePriorPose: CFTimeInterval, _ start: CGFloat, _ length: CGFloat) {
            self.secondsSincePriorPose = secondsSincePriorPose
            self.start = start
            self.length = length
        }
    }

    class var poses: [Pose] {
        get {
            return [
                Pose(0.0, 0.000, 0.7),
                Pose(0.6, 0.500, 0.5),
                Pose(0.6, 1.000, 0.3),
                Pose(0.6, 1.500, 0.1),
                Pose(0.2, 1.875, 0.1),
                Pose(0.2, 2.250, 0.3),
                Pose(0.2, 2.625, 0.5),
                Pose(0.2, 3.000, 0.7),
            ]
        }
    }

    func animate() {
        var time: CFTimeInterval = 0
        var times = [CFTimeInterval]()
        var start: CGFloat = 0
        var rotations = [CGFloat]()
        var strokeEnds = [CGFloat]()

        let poses = type(of: self).poses
        let totalSeconds = poses.reduce(0) { $0 + $1.secondsSincePriorPose }

        for pose in poses {
            time += pose.secondsSincePriorPose
            times.append(time / totalSeconds)
            start = pose.start
            rotations.append(start * 2 * .pi)
            strokeEnds.append(pose.length)
        }

        times.append(times.last!)
        rotations.append(rotations[0])
        strokeEnds.append(strokeEnds[0])

        animateKeyPath(keyPath: "strokeEnd", duration: totalSeconds, times: times, values: strokeEnds)
        animateKeyPath(keyPath: "transform.rotation", duration: totalSeconds, times: times, values: rotations)

        animateStrokeHueWithDuration(duration: totalSeconds * 5)
    }

    func animateKeyPath(keyPath: String, duration: CFTimeInterval, times: [CFTimeInterval], values: [CGFloat]) {
        let animation = CAKeyframeAnimation(keyPath: keyPath)
        animation.keyTimes = times as [NSNumber]?
        animation.values = values
        animation.calculationMode = .linear
        animation.duration = duration
        animation.repeatCount = Float.infinity
        layer.add(animation, forKey: animation.keyPath)
    }

    func animateStrokeHueWithDuration(duration: CFTimeInterval) {
        let count = 36
        let animation = CAKeyframeAnimation(keyPath: "strokeColor")
        animation.keyTimes = (0 ... count).map { NSNumber(value: CFTimeInterval($0) / CFTimeInterval(count)) }
        animation.values = (0 ... count).map {
            UIColor(hue: CGFloat($0) / CGFloat(count), saturation: 1, brightness: 1, alpha: 1).cgColor
        }
        animation.duration = duration
        animation.calculationMode = .linear
        animation.repeatCount = Float.infinity
        layer.add(animation, forKey: animation.keyPath)
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 如何将它添加到我的视图控制器中?`let spinner:SpinnerView = SpinnerView(frame: CGRect(x:0, y: 0, width: 120, height: 120)); self.view.addSubview(spinner);` 我看不到它:/ (3认同)
  • 对于**Swift 3**:layerClass现在作为Swift中的计算类属性导入.所以对于图层类,你应该使用它:`override class var layerClass:AnyClass {return CAShapeLayer.self}` (2认同)