一: 效果
a: 图形做 bounds动画
b: 线条做跟随动画
c: 圆点逐渐呈现动画
d: 图标做轨迹动画
二:代码
static let animationDucation: CFTimeInterval = 3
override func viewDidLoad() {
super.viewDidLoad()
// MARK: 矩形 动画部分
let path = UIBezierPath()
path.move(to: CGPoint(x: 20, y: 300)) // 起点
path.addLine(to: CGPoint(x: 40, y: 100))
path.addLine(to: CGPoint(x: 80, y: 200))
path.addLine(to: CGPoint(x: 150, y: 60))
path.addLine(to: CGPoint(x: 200, y: 100))
path.addLine(to: CGPoint(x: 340, y: 300)) // 右终点
path.addLine(to: CGPoint(x: 20, y: 300)) // 闭圈
let contentLayer = CALayer()
contentLayer.frame = self.view.frame
// 1: 画一个自下而上的渐变图
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x: 0, y: 0, width: 0, height: 300)
gradientLayer.startPoint = CGPoint(x: 0, y: 1)
gradientLayer.endPoint = CGPoint(x: 0, y: 0)
gradientLayer.colors = [
UIColor(red: 185 / 255.0, green: 185 / 255.0, blue: 200 / 255.0, alpha: 1).cgColor,
UIColor(red: 240 / 255.0, green: 240 / 255.0, blue: 240 / 255.0, alpha: 1).cgColor]
gradientLayer.locations = [0.01, 0.5] // colors 元素的起点
contentLayer.addSublayer(gradientLayer)
// 2: 用贝塞尔构建的形状 贴住渐变图(图形以外不可见)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.green.cgColor
contentLayer.mask = shapeLayer
self.view.layer.addSublayer(contentLayer)
// Animation
let animation = CABasicAnimation(keyPath: "bounds")
animation.duration = ProfileViewController.animationDucation
// toValue width 是 frame width的 2 倍,不然动画不完全 不知道为什么
animation.toValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: 680, height: 300))
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.fillMode = .forwards
animation.autoreverses = false
animation.isRemovedOnCompletion = false
gradientLayer.add(animation, forKey: "bounds")
// MARK: 滚动线条 部分
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: 20, y: 300)) // 起点
linePath.addLine(to: CGPoint(x: 40, y: 100))
linePath.addLine(to: CGPoint(x: 80, y: 200))
linePath.addLine(to: CGPoint(x: 150, y: 60))
linePath.addLine(to: CGPoint(x: 200, y: 100))
linePath.addLine(to: CGPoint(x: 340, y: 300)) // 右终点
let lineShapeLayer = CAShapeLayer()
lineShapeLayer.path = linePath.cgPath
lineShapeLayer.strokeColor = UIColor.red.cgColor
lineShapeLayer.fillColor = nil
lineShapeLayer.lineWidth = 1
self.view.layer.addSublayer(lineShapeLayer)
// Animation
let lineAnimation = CABasicAnimation(keyPath: "strokeEnd")
lineAnimation.duration = ProfileViewController.animationDucation
lineAnimation.fromValue = 0
lineAnimation.toValue = 1
lineAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
lineAnimation.fillMode = .forwards
lineAnimation.autoreverses = false
lineAnimation.isRemovedOnCompletion = false
lineShapeLayer.add(lineAnimation, forKey: "strokeEnd")
// MARK: 小圆点部分
let circlePath = UIBezierPath()
circlePath.move(to: CGPoint(x: 40, y: 100))
circlePath.addArc(withCenter: CGPoint(x: 40, y: 100), radius: 10, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
circlePath.move(to: CGPoint(x: 80, y: 200))
circlePath.addArc(withCenter: CGPoint(x: 80, y: 200), radius: 10, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
circlePath.move(to: CGPoint(x: 150, y: 60))
circlePath.addArc(withCenter: CGPoint(x: 150, y: 60), radius: 10, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
circlePath.move(to: CGPoint(x: 200, y: 100))
circlePath.addArc(withCenter: CGPoint(x: 200, y: 100), radius: 10, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
let circleShapeLayer = CAShapeLayer()
circleShapeLayer.path = circlePath.cgPath
circleShapeLayer.fillColor = UIColor(red: 185 / 255.0, green: 185 / 255.0, blue: 200 / 255.0, alpha: 1).cgColor
circleShapeLayer.lineWidth = 1
self.view.layer.addSublayer(circleShapeLayer)
// Animation
let circleAnimation = CABasicAnimation(keyPath: "opacity")
circleAnimation.duration = ProfileViewController.animationDucation
circleAnimation.fromValue = 0.3
circleAnimation.toValue = 1
circleAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
circleAnimation.fillMode = .forwards
circleAnimation.autoreverses = false
circleAnimation.isRemovedOnCompletion = false
circleShapeLayer.add(circleAnimation, forKey: "opacity")
// MARK: 小图标部分
let carLayer: CALayer = CALayer()
carLayer.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
carLayer.contents = UIImage.init(named: "sharelogo")!.cgImage
let carAnimation = CAKeyframeAnimation.init(keyPath: "position")
carAnimation.path = linePath.cgPath
carAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
carAnimation.duration = 6
carAnimation.repeatCount = MAXFLOAT
carAnimation.autoreverses = false
carAnimation.calculationMode = .cubicPaced
carAnimation.rotationMode = .rotateAuto
self.view.layer.addSublayer(carLayer)
carLayer.add(carAnimation, forKey: "carAnimation")
}