123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- //
- // ActivityIndicatorAnimationNewtonCradle.swift
- // IBAnimatable
- //
- // Created by phimage on 29/06/2018.
- // Copyright © 2018 IBAnimatable. All rights reserved.
- //
- import UIKit
- public class ActivityIndicatorAnimationNewtonCradle: ActivityIndicatorAnimating {
- // MARK: Properties
- fileprivate let duration: CFTimeInterval = 0.4
- fileprivate let ratio: CGFloat = 7
- fileprivate let ballCount: Int = 5
- fileprivate let timingFunction: TimingFunctionType = .easeOutQuad
- 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
- var balls: [CALayer] = []
- for _ in 0 ..< ballCount {
- let ball = ActivityIndicatorShape.circle.makeLayer(size: CGSize(width: ballSize, height: ballSize), color: color)
- ball.frame = CGRect(x: xPos, y: yPos, width: ballSize, height: ballSize)
- balls.append(ball)
- xPos += ballSize
- }
- let firstBall = balls.removeFirst()
- firstBall.add(makeAnimation(for: firstBall, in: layer, size: size, reverse: true), forKey: "animation")
- layer.addSublayer(firstBall)
- let lastBall = balls.removeLast()
- lastBall.add(makeAnimation(for: lastBall, in: layer, size: size, reverse: false), forKey: "animation")
- layer.addSublayer(lastBall)
- for ball in balls {
- layer.addSublayer(ball)
- }
- }
- }
- private extension ActivityIndicatorAnimationNewtonCradle {
- func makeAnimation(for ball: CALayer, in layer: CALayer, size: CGSize, reverse: Bool) -> CAAnimation {
- let rotateAnimation = CAKeyframeAnimation(keyPath: .position)
- rotateAnimation.path = UIBezierPath(arcCenter: CGPoint(x: ball.frame.origin.x + ballSize / 2, y: size.height / 2),
- radius: size.height / 2,
- startAngle: CGFloat.pi / 2,
- endAngle: reverse ? CGFloat.pi: 0,
- clockwise: reverse).cgPath
- rotateAnimation.duration = duration
- rotateAnimation.autoreverses = true
- rotateAnimation.timingFunctionType = timingFunction
- if reverse {
- rotateAnimation.beginTime = duration * 2
- }
- let animation = CAAnimationGroup()
- animation.animations = [rotateAnimation]
- animation.duration = duration * 4
- animation.repeatCount = .infinity
- animation.isRemovedOnCompletion = false
- return animation
- }
- }
|