第一次实现加购动画,小小记录一下
需求效果图
代码实现
class AnimationTools: NSObject {
static let shared = AnimationTools()
private var layer: CALayer?
private var toView: UIView?
var animationDidCompete: (() -> Void)?
func startAnimation(fromView: UIView, toView: UIView, sourceViewController: UIViewController) {
self.toView = toView
layer = CALayer()
layer?.contents = fromView.layer.contents
layer?.backgroundColor = UIColor.blue.cgColor
// 图层对齐方式
layer?.contentsGravity = .resizeAspectFill
layer?.frame = fromView.frame
layer?.cornerRadius = fromView.frame.size.height / 2.0
layer?.masksToBounds = true
sourceViewController.view.layer.addSublayer(layer!)
let halfWidth: CGFloat = fromView.frame.width / 2.0
createAnimation(to: CGPoint(x: toView.frame.minX + toView.frame.width / 2.0, y: toView.frame.maxY), controlPoint1: CGPoint(x: fromView.frame.minX + halfWidth, y: fromView.frame.minY + halfWidth), controlPoint2: CGPoint(x: 30, y: fromView.frame.maxY))
}
/// 路径
func createAnimation(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint) {
// 透明动画
let alphaAnimation = CABasicAnimation(keyPath: "opacity")
// 开始值
alphaAnimation.fromValue = 0
// 结束值(绝对值)
alphaAnimation.toValue = 1
// 单位s,1s = 60帧
alphaAnimation.duration = 10 / 60.0
layer?.add(alphaAnimation, forKey: "alphaAnimation")
// 路径动画
let bezierPath = UIBezierPath()
bezierPath.move(to: layer?.position ?? .zero)
bezierPath.addCurve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
let pathAnimation = CAKeyframeAnimation(keyPath: "position")
pathAnimation.path = bezierPath.cgPath
// 缩放动画
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
scaleAnimation.fromValue = 1
scaleAnimation.toValue = 0.2
// 动画组
let groups = CAAnimationGroup()
groups.animations = [pathAnimation, scaleAnimation]
groups.duration = 40 / 60.0
groups.delegate = self
groups.fillMode = .forwards
groups.isRemovedOnCompletion = false
scaleAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
layer?.add(groups, forKey: "addCartGroup")
}
// 呼吸动画, 执行1次
func breathAnimation() {
let breathAnimation = CABasicAnimation(keyPath: "transform.scale")
breathAnimation.fromValue = 1
breathAnimation.toValue = 1.2
// 重复次数
breathAnimation.repeatCount = 1
// 动画结束时执行逆动画
breathAnimation.autoreverses = true
breathAnimation.duration = 5 / 60.0
breathAnimation.isRemovedOnCompletion = false
breathAnimation.delegate = self
toView?.layer.add(breathAnimation, forKey: "countBreath")
}
// 缩放动画,从0-1
func scaleAnimation() {
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
scaleAnimation.fromValue = 0
scaleAnimation.toValue = 1
scaleAnimation.isRemovedOnCompletion = false
scaleAnimation.delegate = self
scaleAnimation.duration = 10 / 60.0
toView?.layer.add(scaleAnimation, forKey: "countSalce")
}
}
extension AnimationTools: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if anim == layer?.animation(forKey: "addCartGroup") {
// 要设置groups.isRemovedOnCompletion = false,这里才会执行
layer?.removeFromSuperlayer()
layer = nil
if toView?.isHidden ?? false {
toView?.isHidden = false
self.scaleAnimation()
} else {
breathAnimation()
}
} else if anim == toView?.layer.animation(forKey: "countSalce") {
breathAnimation()
} else if anim == toView?.layer.animation(forKey: "countBreath") {
self.toView = nil
animationDidCompete?()
}
}
}
啊~这里不能上传.mov,不会生成.gif,在Github中上传了动图效果
Demo地址:AddCartAnimatedDemo
参考文章:
https://developer.apple.com/documentation/quartzcore/cabasicanimation
https://blog.csdn.net/iosevanhuang/article/details/14488239