12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- //
- // ActivityIndicatorAnimationCirclePendulum.swift
- // IBAnimatable
- //
- // Created by phimage on 29/06/2018.
- // Copyright © 2018 IBAnimatable. All rights reserved.
- //
- import Foundation
- import UIKit
- public class ActivityIndicatorAnimationCirclePendulum: ActivityIndicatorAnimating {
- // MARK: Properties
- public var duration: CFTimeInterval = 0.8
- fileprivate let ratio: CGFloat = 7
- fileprivate let ballCount: Int = 3
- #if LG
- public var primaryColor = true
- #else
- public var primaryColor = false
- #endif
- fileprivate let colors: [UIColor] = [.magenta, .yellow, .cyan]
- fileprivate var ballSize: CGFloat = 0
- // MARK: ActivityIndicatorAnimating
- public func configureAnimation(in layer: CALayer, size: CGSize, color: UIColor) {
- ballSize = size.height / ratio
- var xPos = (size.width - (CGFloat(ballCount) * ballSize)) / 2
- let yPos = size.height - ballSize / 2
- for i in 0 ..< ballCount {
- let ball = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: ballSize, height: ballSize), color: primaryColor ? colors[i]: color)
- ball.frame = CGRect(x: xPos, y: yPos, width: ballSize, height: ballSize)
- ball.add(makeAnimation(for: ball, in: layer, size: size, pos: i), forKey: "animation")
- layer.addSublayer(ball)
- xPos += ballSize
- }
- }
- }
- private extension ActivityIndicatorAnimationCirclePendulum {
- func makeAnimation(for ball: CALayer, in layer: CALayer, size: CGSize, pos: Int) -> CAAnimation {
- let angle = 2 * atan(ballSize / (size.height - ballSize / 2))
- var animations: [CAKeyframeAnimation] = [] // only 3 balls, code not generic yet, how to compute angles?
- let rotateAnimation = CAKeyframeAnimation(keyPath: .position)
- var animPos = 0
- rotateAnimation.path = UIBezierPath(arcCenter: CGPoint(x: size.width / 2, y: size.height / 2),
- radius: size.height / 2,
- startAngle: CGFloat.pi / 2 + angle,
- endAngle: 2 * CGFloat.pi + CGFloat.pi / 2 - angle,
- clockwise: true).cgPath
- rotateAnimation.duration = duration
- rotateAnimation.timingFunctionType = .easeInOut
- rotateAnimation.beginTime = duration * CFTimeInterval((pos + animPos) % ballCount)
- animations.append(rotateAnimation)
- let rotateAnimation2 = CAKeyframeAnimation(keyPath: .position)
- animPos += 1
- rotateAnimation2.path = UIBezierPath(arcCenter: CGPoint(x: size.width / 2, y: size.height / 2),
- radius: size.height / 2,
- startAngle: 2 * CGFloat.pi + CGFloat.pi / 2 - angle,
- endAngle: 2 * CGFloat.pi + CGFloat.pi / 2,
- clockwise: true).cgPath
- rotateAnimation2.duration = duration
- rotateAnimation2.timingFunctionType = .easeOutExpo
- rotateAnimation2.beginTime = duration * CFTimeInterval((pos + animPos) % ballCount)
- animations.append(rotateAnimation2)
- let rotateAnimation3 = CAKeyframeAnimation(keyPath: .position)
- animPos += 1
- rotateAnimation3.path = UIBezierPath(arcCenter: CGPoint(x: size.width / 2, y: size.height / 2),
- radius: size.height / 2,
- startAngle: 2 * CGFloat.pi + CGFloat.pi / 2,
- endAngle: 2 * CGFloat.pi + CGFloat.pi / 2 + angle,
- clockwise: true).cgPath
- rotateAnimation3.duration = duration
- rotateAnimation3.timingFunctionType = .easeOutExpo
- rotateAnimation3.beginTime = duration * CFTimeInterval((pos + animPos) % ballCount)
- animations.append(rotateAnimation3)
- let animation = CAAnimationGroup()
- animation.animations = animations
- animation.duration = duration * CFTimeInterval(ballCount)
- animation.repeatCount = .infinity
- animation.isRemovedOnCompletion = false
- return animation
- }
- }
|