123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- //
- // Created by Tom Baranes on 23/08/16.
- // Copyright © 2016 IBAnimatable. All rights reserved.
- //
- import UIKit
- public class ActivityIndicatorAnimationOrbit: ActivityIndicatorAnimating {
- // MARK: Properties
- fileprivate let duration: CFTimeInterval = 1.9
- fileprivate let satelliteCoreRatio: CGFloat = 0.25
- fileprivate let distanceRatio: CGFloat = 1.5
- fileprivate var coreSize: CGFloat = 0
- fileprivate var satelliteSize: CGFloat = 0
- fileprivate var size: CGSize = .zero
- // MARK: ActivityIndicatorAnimating
- public func configureAnimation(in layer: CALayer, size: CGSize, color: UIColor) {
- self.size = size
- coreSize = size.width / (1 + satelliteCoreRatio + distanceRatio)
- satelliteSize = coreSize * satelliteCoreRatio
- animateRing1(in: layer, color: color)
- animateRing2(in: layer, color: color)
- animateCore(in: layer, color: color)
- animateSatellite(in: layer, color: color)
- }
- }
- // MARK: - Satellite
- private extension ActivityIndicatorAnimationOrbit {
- func animateSatellite(in layer: CALayer, color: UIColor) {
- let rotateAnimation = makeSatelliteRotateAnimation(layer: layer)
- let circle = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: satelliteSize, height: satelliteSize), color: color)
- let frame = CGRect(x: 0, y: 0, width: satelliteSize, height: satelliteSize)
- circle.frame = frame
- circle.add(rotateAnimation, forKey: "animation")
- layer.addSublayer(circle)
- }
- func makeSatelliteRotateAnimation(layer: CALayer) -> CAKeyframeAnimation {
- let rotateAnimation = CAKeyframeAnimation(keyPath: .position)
- rotateAnimation.path = UIBezierPath(arcCenter: CGPoint(x: layer.bounds.midX, y: layer.bounds.midY),
- radius: (size.width - satelliteSize) / 2,
- startAngle: CGFloat.pi * 1.5,
- endAngle: CGFloat.pi * 1.5 + 4 * CGFloat.pi,
- clockwise: true).cgPath
- rotateAnimation.duration = duration * 2
- rotateAnimation.repeatCount = .infinity
- rotateAnimation.isRemovedOnCompletion = false
- return rotateAnimation
- }
- }
- // MARK: - Core
- private extension ActivityIndicatorAnimationOrbit {
- func animateCore(in layer: CALayer, color: UIColor) {
- let circle = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: coreSize, height: coreSize), color: color)
- let frame = CGRect(x: (layer.bounds.size.width - coreSize) / 2,
- y: (layer.bounds.size.height - coreSize) / 2,
- width: coreSize,
- height: coreSize)
- circle.frame = frame
- circle.add(coreScaleAnimation, forKey: "animation")
- layer.addSublayer(circle)
- }
- var coreScaleAnimation: CAKeyframeAnimation {
- let inTimingFunction: TimingFunctionType = .custom((0.7, 0), (1, 0.5))
- let outTimingFunction: TimingFunctionType = .custom(( 0, 0.7), (0.5, 1))
- let standByTimingFunction: TimingFunctionType = .linear
- let scaleAnimation = CAKeyframeAnimation(keyPath: .scale)
- scaleAnimation.keyTimes = [0, 0.45, 0.55, 1]
- scaleAnimation.timingFunctionsType = [inTimingFunction, standByTimingFunction, outTimingFunction]
- scaleAnimation.values = [1, 1.3, 1.3, 1]
- scaleAnimation.duration = duration
- scaleAnimation.repeatCount = .infinity
- scaleAnimation.isRemovedOnCompletion = false
- return scaleAnimation
- }
- }
- // MARK: - Ring 1
- private extension ActivityIndicatorAnimationOrbit {
- func animateRing1(in layer: CALayer, color: UIColor) {
- let animation = ring1Animation
- let circle = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: coreSize, height: coreSize), color: color)
- let frame = CGRect(x: (layer.bounds.size.width - coreSize) / 2,
- y: (layer.bounds.size.height - coreSize) / 2,
- width: coreSize,
- height: coreSize)
- circle.frame = frame
- circle.add(animation, forKey: "animation")
- layer.addSublayer(circle)
- }
- var ring1Animation: CAAnimationGroup {
- let animation = CAAnimationGroup()
- animation.animations = [ring1ScaleAnimation, ring1OpacityAnimation]
- animation.duration = duration
- animation.repeatCount = .infinity
- animation.isRemovedOnCompletion = false
- return animation
- }
- var ring1ScaleAnimation: CAKeyframeAnimation {
- let scaleAnimation = CAKeyframeAnimation(keyPath: .scale)
- scaleAnimation.keyTimes = [0, 0.45, 0.45, 1]
- scaleAnimation.timingFunctionType = .linear
- scaleAnimation.values = [0, 0, 1.3, 2]
- scaleAnimation.duration = duration
- return scaleAnimation
- }
- var ring1OpacityAnimation: CAKeyframeAnimation {
- let opacityAnimation = CAKeyframeAnimation(keyPath: .opacity)
- opacityAnimation.keyTimes = [0, 0.45, 1]
- opacityAnimation.timingFunctionsType = [.linear, .easeOutExpo]
- opacityAnimation.values = [0.8, 0.8, 0]
- opacityAnimation.duration = duration
- return opacityAnimation
- }
- }
- // MARK: - Ring 2
- private extension ActivityIndicatorAnimationOrbit {
- func animateRing2(in layer: CALayer, color: UIColor) {
- let animation = ring2Animation
- let circle = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: coreSize, height: coreSize), color: color)
- let frame = CGRect(x: (layer.bounds.size.width - coreSize) / 2,
- y: (layer.bounds.size.height - coreSize) / 2,
- width: coreSize,
- height: coreSize)
- circle.frame = frame
- circle.add(animation, forKey: "animation")
- layer.addSublayer(circle)
- }
- var ring2Animation: CAAnimationGroup {
- let animation = CAAnimationGroup()
- animation.animations = [ring2ScaleAnimation, ring2OpacityAnimation]
- animation.duration = duration
- animation.repeatCount = .infinity
- animation.isRemovedOnCompletion = false
- return animation
- }
- var ring2ScaleAnimation: CAKeyframeAnimation {
- let scaleAnimation = CAKeyframeAnimation(keyPath: .scale)
- scaleAnimation.keyTimes = [0, 0.55, 0.55, 1]
- scaleAnimation.timingFunctionType = .linear
- scaleAnimation.values = [0, 0, 1.3, 2.1]
- scaleAnimation.duration = duration
- return scaleAnimation
- }
- var ring2OpacityAnimation: CAKeyframeAnimation {
- let opacityAnimation = CAKeyframeAnimation(keyPath: .opacity)
- opacityAnimation.keyTimes = [0, 0.55, 0.65, 1]
- opacityAnimation.timingFunctionsType = [.linear, .easeOutExpo]
- opacityAnimation.values = [0.7, 0.7, 0, 0]
- opacityAnimation.duration = duration
- return opacityAnimation
- }
- }
|