一、核心动画种类
1.基础动画
2.转场动画
3.弹簧动画
4.关键帧动画
5.动画组(对上面的动画合并的一种说法)
二、上代码
- 基础动画
class BasicAnimaViewController: UIViewController {
var redView: UIView!
// 动画key
let position = "position" // 位移
/**
* 旋转
*/
let zRotation = "transform.rotation"
let xRotation = "transform.rotation.x"
let yRotation = "transform.rotation.y"
/**
* 缩放
*/
let zScale = "transform.scale"
let xScale = "transform.scale.x"
let yScale = "transform.scale.y"
/**
* transform 动画
*/
let transformAnim = "transform"
// 自定义动画的key
let kMoveredViewAnima = "kMoveredViewAnima"
let kZRotation = "kZRotation"
let kXRotation = "kXRotation"
let kYRotation = "kYRotation"
let kZScale = "kZScale"
let kXScale = "kXScale"
let kYScale = "kYScale"
override func viewDidLoad() {
super.viewDidLoad()
self.title = "基础动画"
redView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 70))
redView.backgroundColor = .red
view.addSubview(redView)
// simpleMove()
// RotationZ()
// RotationX()
// RotationY()
// scaleY()
transformAnimation()
}
func simpleMove() {
// 简单位移
let animation = CABasicAnimation(keyPath: position)
animation.fromValue = redView.center
animation.toValue = CGPoint(x:redView.center.x,y:redView.center.y + 100)
animation.repeatCount = 2
animation.duration = 3
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kMoveredViewAnima)
}
func RotationZ() {
let animation = CABasicAnimation(keyPath: zRotation)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 0
animation.toValue = .pi * 2.0
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kZRotation)
}
func RotationX() {
let animation = CABasicAnimation(keyPath: xRotation)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 0
animation.toValue = .pi * 2.0
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kXRotation)
}
func RotationY() {
let animation = CABasicAnimation(keyPath: yRotation)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 0
animation.toValue = .pi * 2.0
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kYRotation)
}
func scaleZ() {
let animation = CABasicAnimation(keyPath: zScale)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 1
animation.toValue = 1.5
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kZScale)
}
func scaleX() {
let animation = CABasicAnimation(keyPath: xScale)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 1
animation.toValue = 1.5
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kXScale)
}
func scaleY() {
let animation = CABasicAnimation(keyPath: yScale)
animation.repeatCount = 2
animation.duration = 3
animation.fromValue = 1
animation.toValue = 1.5
animation.beginTime = CACurrentMediaTime() + 1
redView.layer.add(animation, forKey: kYScale)
}
func transformAnimation() { // ?
let animation = CABasicAnimation(keyPath: transformAnim)
animation.repeatCount = 5
animation.duration = 3
// animation.fromValue = 1
// animation.toValue = 1.5
animation.beginTime = CACurrentMediaTime() + 1
var transform = CATransform3DMakeRotation(CGFloat(Double.pi), 1, 1, 1)
// transform.m34 = -1.0/600.0
animation.byValue = transform
redView.layer.add(animation, forKey: kYScale)
}
}
- 转场动画
class translationAnimaViewController: UIViewController {
let imageView = UIImageView()
// type
let typeRippleEffect = "rippleEffect"
override func viewDidLoad() {
super.viewDidLoad()
self.title = "转场动画"
setUI()
}
func setUI() {
imageView.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
// imageView.center = view.center
imageView.image = UIImage(named: "abc")
view.addSubview(imageView)
let btn = UIButton(type: .custom)
btn.frame = CGRect(x: 0, y: view.bounds.height - 150, width: 50, height: 30)
btn.center = CGPoint(x: view.bounds.width/2.0 - 100, y: view.bounds.height - 130)
btn.backgroundColor = .green
btn.setTitle("切换", for: .normal)
btn.addTarget(self, action: #selector(change(_:)), for: .touchUpInside)
view.addSubview(btn)
}
/**
fade:默认,交叉淡化过渡,不支持过渡方向,OC中对应的常量为kCATransitionFade
push:新视图把旧视图推出去,OC中对应的常量为kCATransitionPush
moveIn:新视图移到旧视图上面,对应的常量为kCATransitionMoveIn
reveal:将旧视图移开显示下边的新视图,对应的常量为kCATransitionReveal
cube:立方体反转效果
oglFlip:上下左右反转效果
suckEffect:收缩效果,如一块布被抽走,不支持过渡方向
rippleEffect:滴水效果,不支持过渡方向
pageCurl:向上翻页效果
pageUnCurl:向下翻页效果
cameraIrisHollowOpen:相机镜头打开效果,不支持过渡方向
cameraIrisHollowClose:相机镜头关闭效果,不支持过渡方向
*/
@objc func change(_ sender: UIButton) {
let animation = CATransition()
animation.type = CATransitionType(rawValue: "push")
animation.duration = 3
animation.subtype = .fromTop
animation.fillMode = .forwards
imageView.layer.add(animation, forKey: "change")
imageView.image = UIImage(named: "001")
}
}
- 弹簧动画
class SpringAnimaViewController: UIViewController {
var redView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "弹簧动画"
redView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 70))
redView.backgroundColor = .red
view.addSubview(redView)
CASpringAnim()
}
func springAnim() {
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.6, options: [.autoreverse,.repeat]) {
self.redView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
} completion: { _ in
}
}
func CASpringAnim() {
let animtion = CASpringAnimation(keyPath: "transform.scale")
animtion.beginTime = CACurrentMediaTime()
animtion.mass = 0.1 // 质量越大,惯性越大
animtion.damping = 1 // 阻尼系数
animtion.stiffness = 100 // 刚性系数,刚性系数越大,运动越快
animtion.initialVelocity = 0.3 // 初始速率
animtion.toValue = 1.5
animtion.repeatCount = HUGE
animtion.autoreverses = false
animtion.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
animtion.duration = animtion.settlingDuration // 系统根据动画参数估算的时间
redView.layer.add(animtion, forKey: "CASpringAnim")
}
}
- 关键帧动画
class keyFrameViewController: UIViewController {
var redView: UIView!
// 动画key
let position = "position" // 位移
let zRotation = "transform.rotation"
// 自定义动画的key
let kMoveredViewAnima = "kMoveredViewAnima"
let kShakeAnim = "kShakeAnim"
let kTranslate = "kTranslate"
override func viewDidLoad() {
super.viewDidLoad()
self.title = "关键帧动画"
redView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 70))
redView.backgroundColor = .red
view.addSubview(redView)
renderM()
}
func simpleMove() {
// 简单位移
let animation = CAKeyframeAnimation(keyPath: position)
animation.repeatCount = 2
animation.duration = 3
// 移动轨迹
animation.values = [redView.center,CGPoint(x: 200, y: 200),CGPoint(x: 200, y: 300)]
// 每段路程经过的时间,时间节点比例
animation.keyTimes = [NSNumber(value: 0.0),NSNumber(value: 0.7),NSNumber(value: 1.0),]
animation.beginTime = CACurrentMediaTime() + 1
animation.isRemovedOnCompletion = false
animation.autoreverses = true
// 拐弯的地方轨迹变平滑
animation.calculationMode = .cubic
redView.layer.add(animation, forKey: kMoveredViewAnima)
}
func simpleMoveByPath() {
// 简单位移
let animation = CAKeyframeAnimation(keyPath: position)
animation.repeatCount = 2
animation.duration = 3
// 移动轨迹
animation.values = [redView.center,CGPoint(x: 200, y: 200),CGPoint(x: 200, y: 300)] // 失效
// 每段路程经过的时间,时间节点比例
// animation.keyTimes = [NSNumber(value: 0.0),NSNumber(value: 0.7),NSNumber(value: 1.0),]
animation.beginTime = CACurrentMediaTime() + 1
animation.isRemovedOnCompletion = false
animation.autoreverses = true
// 拐弯的地方轨迹变平滑
// animation.calculationMode = .cubic
// 添加path,values失效
let path = CGMutablePath()
path.addArc(center: view.center, radius: 100, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true)
animation.path = path
redView.layer.add(animation, forKey: kMoveredViewAnima)
}
func shakeAnim() {
let label = UILabel(frame: redView.bounds)
label.textAlignment = .center
label.textColor = .white
label.text = "摇一摇"
redView.addSubview(label)
let animation = CAKeyframeAnimation(keyPath: zRotation)
animation.duration = 0.3
let angle = Double.pi/6.0
animation.values = [angle, -angle]
animation.repeatCount = 3
animation.autoreverses = true
animation.calculationMode = .cubicPaced
redView.layer.add(animation, forKey: kShakeAnim)
}
func renderM() {
let label = UILabel(frame: redView.bounds)
label.textAlignment = .center
label.textColor = .white
label.text = "画M"
redView.addSubview(label)
let animation = CAKeyframeAnimation(keyPath: position)
animation.duration = 5
let path = CGMutablePath()
path.move(to: CGPoint(x: 40, y: 300))
path.addLine(to: CGPoint(x: 80, y: 150))
path.addLine(to: CGPoint(x: 120, y: 300))
path.addLine(to: CGPoint(x: 160, y: 150))
path.addLine(to: CGPoint(x: 200, y: 300))
animation.path = path
animation.repeatCount = HUGE
// animation.rotationMode = .rotateAuto // 跟随运动方向自旋转
animation.calculationMode = .cubicPaced
animation.fillMode = .forwards
redView.layer.add(animation, forKey: kTranslate)
}
}
- 动画组
class AnimaGroupViewController: UIViewController {
let imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "动画组"
setUI()
}
func setUI() {
imageView.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
imageView.image = UIImage(named: "001")
view.addSubview(imageView)
let btn = UIButton(type: .custom)
btn.frame = CGRect(x: 160, y: 250, width: 80, height: 40)
btn.setTitle("切换", for: .normal)
btn.backgroundColor = .blue
btn.addTarget(self, action: #selector(change(_:)), for: .touchUpInside)
view.addSubview(btn)
}
@objc func change(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
let transition = CABasicAnimation(keyPath: "position")
transition.toValue = CGPoint(x: 100, y: 400)
// transition.autoreverses = true
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.fromValue = 0
rotation.toValue = Double.pi * 2
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.toValue = 0.5
let group = CAAnimationGroup()
group.animations = [transition, rotation, scale]
group.repeatCount = HUGE
group.duration = 2
group.autoreverses = true
imageView.layer.add(group, forKey: "group")
} else {
imageView.layer.removeAllAnimations()
}
}
}