So I'm trying to learn how to draw circles in UIKit and I've got them pretty much figured it out but I'm just trying to implement one more thing. In the video below when the tail of the circle reaches the end I would like for the tail to not reach the head fully, meaning I would like the size of the circle to not shrink completely.
I sort of have it in the video below but there is still the snap were the tails goes away and the animation starts again at the head. So I would like the disappearance of the tail to not go away.
Video Demo: https://github.com/DJSimonSays93/CircleAnimation/blob/main/README.md
Here is the code:
class SpinningView: UIView {
let circleLayer = CAShapeLayer()
let rotationAnimation: CAAnimation = {
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = 0
animation.toValue = Double.pi * 2
animation.duration = 3 // increase this duration to slow down the circle animation effect
animation.repeatCount = MAXFLOAT
return animation
}()
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
func setup() {
circleLayer.lineWidth = 10.0
circleLayer.fillColor = nil
//circleLayer.strokeColor = UIColor(red: 0.8078, green: 0.2549, blue: 0.2392, alpha: 1.0).cgColor
circleLayer.strokeColor = UIColor.systemBlue.cgColor
circleLayer.lineCap = .round
layer.addSublayer(circleLayer)
updateAnimation()
}
override func layoutSubviews() {
super.layoutSubviews()
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = min(bounds.width, bounds.height) / 2 - circleLayer.lineWidth / 2
let startAngle: CGFloat = -90.0
let endAngle: CGFloat = startAngle + 360.0
circleLayer.position = center
circleLayer.path = createCircle(startAngle: startAngle, endAngle: endAngle, radius: radius).cgPath
}
private func updateAnimation() {
//The strokeStartAnimation beginTime + duration value need to add up to the strokeAnimationGroup.duration value
let strokeStartAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeStart")
strokeStartAnimation.beginTime = 0.5
strokeStartAnimation.fromValue = 0
strokeStartAnimation.toValue = 0.93 //change this to 0.93 for cool effect
strokeStartAnimation.duration = 3.0
strokeStartAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
let strokeEndAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
strokeEndAnimation.fromValue = 0
strokeEndAnimation.toValue = 1.0
strokeEndAnimation.duration = 2.0
strokeEndAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
let colorAnimation = CABasicAnimation(keyPath: "strokeColor")
colorAnimation.fromValue = UIColor.systemBlue.cgColor
colorAnimation.toValue = UIColor.systemRed.cgColor
let strokeAnimationGroup: CAAnimationGroup = CAAnimationGroup()
strokeAnimationGroup.duration = 3.5
strokeAnimationGroup.repeatCount = Float.infinity
strokeAnimationGroup.fillMode = .forwards
strokeAnimationGroup.isRemovedOnCompletion = false
strokeAnimationGroup.animations = [strokeStartAnimation, strokeEndAnimation, colorAnimation]
circleLayer.add(strokeAnimationGroup, forKey: nil)
circleLayer.add(rotationAnimation, forKey: "rotation")
}
private func createCircle(startAngle: CGFloat, endAngle: CGFloat, radius: CGFloat) -> UIBezierPath {
return UIBezierPath(arcCenter: CGPoint.zero,
radius: radius,
startAngle: startAngle.toRadians(),
endAngle: endAngle.toRadians(),
clockwise: true)
}