Files
ProgressKit/InDeterminate/MaterialProgress.swift
Kaunteya Suryawanshi 6d011fd523 Cleanup
2018-10-10 12:31:12 +05:30

125 lines
4.1 KiB
Swift

//
// MaterialProgress.swift
// ProgressKit
//
// Created by Kauntey Suryawanshi on 30/06/15.
// Copyright (c) 2015 Kauntey Suryawanshi. All rights reserved.
//
import Foundation
import Cocoa
private let duration = 1.5
private let strokeRange = (start: 0.0, end: 0.8)
@IBDesignable
open class MaterialProgress: IndeterminateAnimation {
@IBInspectable open var lineWidth: CGFloat = -1 {
didSet {
progressLayer.lineWidth = lineWidth
}
}
override func notifyViewRedesigned() {
super.notifyViewRedesigned()
progressLayer.strokeColor = foreground.cgColor
}
var backgroundRotationLayer = CAShapeLayer()
var progressLayer: CAShapeLayer = {
var tempLayer = CAShapeLayer()
tempLayer.strokeEnd = CGFloat(strokeRange.end)
tempLayer.lineCap = .round
tempLayer.fillColor = NSColor.clear.cgColor
return tempLayer
}()
//MARK: Animation Declaration
var animationGroup: CAAnimationGroup = {
var tempGroup = CAAnimationGroup()
tempGroup.repeatCount = 1
tempGroup.duration = duration
return tempGroup
}()
var rotationAnimation: CABasicAnimation = {
var tempRotation = CABasicAnimation(keyPath: "transform.rotation")
tempRotation.repeatCount = Float.infinity
tempRotation.fromValue = 0
tempRotation.toValue = 1
tempRotation.isCumulative = true
tempRotation.duration = duration / 2
return tempRotation
}()
/// Makes animation for Stroke Start and Stroke End
func makeStrokeAnimationGroup() {
var strokeStartAnimation: CABasicAnimation!
var strokeEndAnimation: CABasicAnimation!
func makeAnimationforKeyPath(_ keyPath: String) -> CABasicAnimation {
let tempAnimation = CABasicAnimation(keyPath: keyPath)
tempAnimation.repeatCount = 1
tempAnimation.speed = 2.0
tempAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
tempAnimation.fromValue = strokeRange.start
tempAnimation.toValue = strokeRange.end
tempAnimation.duration = duration
return tempAnimation
}
strokeEndAnimation = makeAnimationforKeyPath("strokeEnd")
strokeStartAnimation = makeAnimationforKeyPath("strokeStart")
strokeStartAnimation.beginTime = duration / 2
animationGroup.animations = [strokeEndAnimation, strokeStartAnimation, ]
animationGroup.delegate = self
}
override func configureLayers() {
super.configureLayers()
makeStrokeAnimationGroup()
let rect = self.bounds
backgroundRotationLayer.frame = rect
self.layer?.addSublayer(backgroundRotationLayer)
// Progress Layer
let radius = (rect.width / 2) * 0.75
progressLayer.frame = rect
progressLayer.lineWidth = lineWidth == -1 ? radius / 10: lineWidth
let arcPath = NSBezierPath()
arcPath.appendArc(withCenter: rect.mid, radius: radius, startAngle: 0, endAngle: 360, clockwise: false)
progressLayer.path = arcPath.CGPath
backgroundRotationLayer.addSublayer(progressLayer)
}
var currentRotation = 0.0
let π2 = Double.pi * 2
override func startAnimation() {
progressLayer.add(animationGroup, forKey: "strokeEnd")
backgroundRotationLayer.add(rotationAnimation, forKey: rotationAnimation.keyPath)
}
override func stopAnimation() {
backgroundRotationLayer.removeAllAnimations()
progressLayer.removeAllAnimations()
}
}
extension MaterialProgress: CAAnimationDelegate {
open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if !animate { return }
CATransaction.begin()
CATransaction.setDisableActions(true)
currentRotation += strokeRange.end * π2
currentRotation = currentRotation.truncatingRemainder(dividingBy: π2)
progressLayer.setAffineTransform(CGAffineTransform(rotationAngle: CGFloat( currentRotation)))
CATransaction.commit()
progressLayer.add(animationGroup, forKey: "strokeEnd")
}
}