| 
7 | 7 | //  | 
8 | 8 | 
 
  | 
9 | 9 | import UIKit  | 
 | 10 | +import Infinity  | 
10 | 11 | 
 
  | 
11 |  | -class SparkInfinityAnimator: UIView {  | 
12 |  | - | 
 | 12 | +class SparkInfinityAnimator: UIView, CustomInfinityScrollAnimator {  | 
 | 13 | +      | 
 | 14 | +    private var circles = [CAShapeLayer]()  | 
 | 15 | +    var animating = false  | 
 | 16 | +      | 
 | 17 | +    private var positions = [CGPoint]()  | 
 | 18 | +      | 
 | 19 | +    override init(frame: CGRect) {  | 
 | 20 | +        super.init(frame: frame)  | 
 | 21 | +          | 
 | 22 | +        let ovalDiameter = min(frame.width,frame.height) / 8  | 
 | 23 | +        let ovalPath = UIBezierPath(ovalInRect: CGRect(x: 0, y: 0, width: ovalDiameter, height: ovalDiameter))  | 
 | 24 | +          | 
 | 25 | +        let count = 8  | 
 | 26 | +        for index in 0..<count {  | 
 | 27 | +            let circleLayer = CAShapeLayer()  | 
 | 28 | +            circleLayer.path = ovalPath.CGPath  | 
 | 29 | +            circleLayer.fillColor = UIColor.sparkColorWithIndex(index).CGColor  | 
 | 30 | +            circleLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)  | 
 | 31 | +              | 
 | 32 | +            self.circles.append(circleLayer)  | 
 | 33 | +            self.layer.addSublayer(circleLayer)  | 
 | 34 | +              | 
 | 35 | +            let angle = CGFloat(M_PI * 2) / CGFloat(count) * CGFloat(index)  | 
 | 36 | +              | 
 | 37 | +            let radius = min(frame.width, frame.height) * 0.4  | 
 | 38 | +            let position = CGPoint(x: bounds.midX + sin(angle) * radius, y: bounds.midY - cos(angle) * radius)  | 
 | 39 | +            circleLayer.position = position  | 
 | 40 | +              | 
 | 41 | +            positions.append(position)  | 
 | 42 | +        }  | 
 | 43 | +    }  | 
 | 44 | +    required init?(coder aDecoder: NSCoder) {  | 
 | 45 | +        fatalError("init(coder:) has not been implemented")  | 
 | 46 | +    }  | 
 | 47 | +    override func didMoveToWindow() {  | 
 | 48 | +        super.didMoveToWindow()  | 
 | 49 | +          | 
 | 50 | +        if window != nil && animating {  | 
 | 51 | +            startAnimating()  | 
 | 52 | +        }  | 
 | 53 | +    }  | 
 | 54 | +      | 
 | 55 | +    func animateState(state: InfinityScrollState) {  | 
 | 56 | +        switch state {  | 
 | 57 | +        case .None:  | 
 | 58 | +            stopAnimating()  | 
 | 59 | +        case .Loading:  | 
 | 60 | +            startAnimating()  | 
 | 61 | +        }  | 
 | 62 | +    }  | 
 | 63 | +    func startAnimating() {  | 
 | 64 | +        animating = true  | 
 | 65 | +        for index in 0..<8 {  | 
 | 66 | +            applyAnimationForIndex(index)  | 
 | 67 | +        }  | 
 | 68 | +    }  | 
 | 69 | +    private let CircleAnimationKey = "CircleAnimationKey"  | 
 | 70 | +    private func applyAnimationForIndex(index: Int) {  | 
 | 71 | +        let moveAnimation = CAKeyframeAnimation(keyPath: "position")  | 
 | 72 | +        let moveV1 = NSValue(CGPoint: positions[index])  | 
 | 73 | +        let moveV2 = NSValue(CGPoint: CGPoint(x: bounds.midX, y: bounds.midY))  | 
 | 74 | +        let moveV3 = NSValue(CGPoint: positions[index])  | 
 | 75 | +        moveAnimation.values = [moveV1,moveV2,moveV3]  | 
 | 76 | +          | 
 | 77 | +        let scaleAnimation = CAKeyframeAnimation(keyPath: "transform")  | 
 | 78 | +        let scaleV1 = NSValue(CATransform3D: CATransform3DIdentity)  | 
 | 79 | +        let scaleV2 = NSValue(CATransform3D: CATransform3DMakeScale(0.1, 0.1, 1.0))  | 
 | 80 | +        let scaleV3 = NSValue(CATransform3D: CATransform3DIdentity)  | 
 | 81 | +        scaleAnimation.values = [scaleV1,scaleV2,scaleV3]  | 
 | 82 | +          | 
 | 83 | +        let animationGroup = CAAnimationGroup()  | 
 | 84 | +        animationGroup.animations = [moveAnimation,scaleAnimation]  | 
 | 85 | +        animationGroup.duration = 1.0  | 
 | 86 | +        animationGroup.repeatCount = 1000  | 
 | 87 | +        animationGroup.beginTime = CACurrentMediaTime() + Double(index) * animationGroup.duration / 8 / 2  | 
 | 88 | +        animationGroup.timingFunction = CAMediaTimingFunction(controlPoints: 1, 0.5, 0, 0.5)  | 
 | 89 | +          | 
 | 90 | +        let circleLayer = circles[index]  | 
 | 91 | +        circleLayer.hidden = false  | 
 | 92 | +        circleLayer.addAnimation(animationGroup, forKey: CircleAnimationKey)  | 
 | 93 | +          | 
 | 94 | +    }  | 
 | 95 | +    func stopAnimating() {  | 
 | 96 | +        for circleLayer in circles {  | 
 | 97 | +            circleLayer.removeAnimationForKey(CircleAnimationKey)  | 
 | 98 | +            circleLayer.transform = CATransform3DIdentity  | 
 | 99 | +            circleLayer.hidden = true  | 
 | 100 | +        }  | 
 | 101 | +        animating = false  | 
 | 102 | +    }  | 
13 | 103 |     /*  | 
14 | 104 |     // Only override drawRect: if you perform custom drawing.  | 
15 | 105 |     // An empty implementation adversely affects performance during animation.  | 
 | 
0 commit comments