如何在 Mac 上实现环形 loading 动画
网上也有很多 loading 动画,但每个公司的需求可能不同,网上找了很多可以在 Mac 上用的,要不和需求融入不方便吗,要么就是有很多多余的功能。
我们的需求不展示进度,展示的是几种状态,状态不同,执行的动画也不同。
我们状态共 4 种:
-
连接中 connecting :圆弧,顺时针旋转
-
连接完成 connected:在连接基础上,把圆弧动画为整圆
-
断开连接中 disconnecting:圆弧,逆时针旋转
-
断开完成 disconected:在上一个动画基础上,把圆弧动画为 0
本想传个 gif 图的,没工具,下了个录不出效果。。。录了个视频,简书md 不支持。。。
下面说下实现思路:
通过自定义 NSView 来实现。主要用到绘图相关的知识。
各个状态的动画分别实现,代码不多,注释很详细,不啰嗦了。
import Cocoa
class LoadingView: NSView {
private var animationLayer:CAShapeLayer!
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
basicInit()
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
basicInit()
}
private func basicInit() {
wantsLayer = true
animationLayer = CAShapeLayer()
layer?.addSublayer(animationLayer)
animationLayer.frame = bounds
// 画圆
let path = CGMutablePath()
let center = CGPoint(x: bounds.width/2, y: bounds.height/2)
path.addArc(center: center, radius: 0.9 * bounds.width/2, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
animationLayer.path = path
// 画边框(r:0.20 g:0.85 b:0.99 a:1.00)
animationLayer.strokeColor = CGColor(red: 0.20, green: 0.85, blue: 0.99, alpha: 1.00)
animationLayer.lineWidth = 5
animationLayer.fillColor = NSColor.clear.cgColor// 清空填充颜色
// 画部分圆环
animationLayer.strokeEnd = 0.2
animationLayer.isHidden = true
// 动画在需要时进行调用
}
// 连接动画
func connectingAnimation() {
animationLayer.isHidden = false
animationLayer.removeAllAnimations()
let rotateAnimtion = CABasicAnimation(keyPath: "transform.rotation.z")
let startValue = NSNumber(value: Float(2.0*CGFloat.pi))
let endValue = NSNumber(value: 0)
rotateAnimtion.fromValue = startValue
rotateAnimtion.toValue = endValue
rotateAnimtion.duration = 1
rotateAnimtion.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
animationLayer.add(rotateAnimtion, forKey: "connecting")
}
// 连接成功动画
func concectedAnimation() {
animationLayer.isHidden = false
let connectedAnimation = CABasicAnimation(keyPath: "strokeEnd")
connectedAnimation.fromValue = NSNumber(value: 0.2)
connectedAnimation.toValue = NSNumber(value: 1)
connectedAnimation.duration = 1
connectedAnimation.delegate = self
animationLayer.add(connectedAnimation, forKey: "connected")
}
// 断开动画
func disconcectAnimation() {
animationLayer.isHidden = false
let connectedAnimation = CABasicAnimation(keyPath: "strokeEnd")
connectedAnimation.toValue = NSNumber(value: 0)
connectedAnimation.duration = 0.5
connectedAnimation.delegate = self
connectedAnimation.fillMode = .forwards
connectedAnimation.isRemovedOnCompletion = false
animationLayer.add(connectedAnimation, forKey: "disconcect")
}
// 断开中动画
func disconnectingAnimation() {
animationLayer.isHidden = false
animationLayer.removeAllAnimations()
let rotateAnimtion = CABasicAnimation(keyPath: "transform.rotation.z")
let startValue = NSNumber(value: Float(2.0*CGFloat.pi))
let endValue = NSNumber(value: 0)
rotateAnimtion.fromValue = endValue
rotateAnimtion.toValue = startValue
rotateAnimtion.duration = 1
rotateAnimtion.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
animationLayer.add(rotateAnimtion, forKey: "disconnecting")
}
}
extension LoadingView:CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
animationLayer.isHidden = true
animationLayer.removeAllAnimations()
}
}
网友评论