//
// EYLayerViewController.swift
// videomask
//
// Created by sjh on 2023/8/8.
//
import UIKit
class EYLayerViewController: UIViewController {
var aniLayer = CALayer.init()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.view.addSubview(backgroundView)
backgroundView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
backgroundView.center = self.view.center
// Do any additional setup after loading the view.
self.view.layer.addSublayer(aniLayer)
//💡layer设置布局建议使用position 和 center
aniLayer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
//设置中心点
aniLayer.position = self.view.center
aniLayer.backgroundColor = UIColor.green.cgColor
//锚点的位置 小于0.5,向右➡️移动。 小于0.5 向下⬇️移动(与坐标系相反)
// aniLayer.anchorPoint = CGPoint.init(x: 1.5, y: 0.5)
// aniLayer.contentsScale = 0.3
// setMask()
//⚠️mask 会影响 shadow
setShadow()
//设置图层代理
aniLayer.delegate = self
//调用此方法,否则代理方法不会被调用
aniLayer.setNeedsDisplay()
}
func setShadow(){
/*🔔
1.masksToBounds 目的就是剪切外边框
2.而shadow 正好在外边框上
3.如果要显示圆角阴影,可以考虑2个layer去做
*/
// aniLayer.cornerRadius = 25
// aniLayer.masksToBounds = true
//阴影位置 小于0,出现在左边。 小于0 出现在上班(与坐标系对应)
// aniLayer.shadowOffset = CGSize(width: -2, height: -2)
aniLayer.shadowColor = UIColor.red.cgColor
aniLayer.shadowOpacity = 1
//后面展现一个一个半径的阴影
aniLayer.shadowRadius = 25
}
func setMask(){
let mask = CALayer.init()
//遮罩区域
mask.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
//🔔 遮罩 过大可以显示shadow
// mask.bounds = CGRect(x: 0, y: 0, width: 120, height: 120)
mask.position = CGPoint(x: 50, y: 50)
//显示的透明度 0 透明 -> 1不透明
mask.opacity = 1
//设置颜色并没有作用。但是可以使aniLayer 遮罩区域显示出来
mask.backgroundColor = UIColor.red.cgColor
mask.borderWidth = 3
mask.borderColor = UIColor.darkGray.cgColor
//背景同时消失了
// mask.isHidden = true
let scale_ani = aniLayer.contentsScale
let scale_mask = mask.contentsScale
EYLog(M: "scale_ani = \(scale_ani),scale_mask = \(scale_mask)")
aniLayer.mask = mask
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
aniLayer.add(basicAnimation, forKey: "position")
// aniLayer.add(keyframeAnimation_1, forKey: "transform.rotation")
// aniLayer.add(keyframeAnimation_2, forKey: "position")#imageLiteral(resourceName: "simulator_screenshot_FA85362A-AA46-412F-A446-473496B53DDF.png")
// aniLayer.add(transitionAnimation, forKey: "test")
// aniLayer.add(groupAnimation, forKey: "group")
// keyframeAnimation_1()
// keyframeAnimation_2()
// springAnimation()
// transitionAnimation()
// groupAnimation()
}
//CABasicAnimation 基本动画
/*
keyPath
1.position
2.position.y
3.position.x
4.transform
5.transform.x
6.transform.y
7.bounds
8.bounds.width
*/
lazy var basicAnimation: CABasicAnimation = {
let ani = CABasicAnimation.init(keyPath: "position")
ani.repeatCount = 1
//默认YES, 代表动画执行完成后从图层移除。 图层恢复到之前的状态
// ani.isRemovedOnCompletion = true
//图层保持动画后的状态
ani.isRemovedOnCompletion = false
//决定当前对象在非active时间段的行为
ani.fillMode = .forwards
//动画开始时间 如: 延迟2s
ani.beginTime = CACurrentMediaTime() + 2
//动画时长
ani.duration = 3;
//线性,匀速
ani.timingFunction = CAMediaTimingFunction.init(name: .linear)
//渐进 慢-快
ani.timingFunction = CAMediaTimingFunction.init(name: .easeIn)
//渐出 快-慢
ani.timingFunction = CAMediaTimingFunction.init(name: .easeOut)
//渐进渐出 慢-快-慢
ani.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
//起始值 这里指position
// ani.fromValue = NSValue(cgPoint: CGPointMake(100, 100))
//插入值 toValue-byValue 开始
ani.byValue = NSValue(cgPoint: CGPoint(x: 200, y: 400))
//结束值 这里指position
ani.toValue = NSValue(cgPoint: CGPointMake(150, 350))
//支持键值编码
ani.setValue("form", forKey: "name")
ani.setValue(aniLayer, forKey: "layer")
return ani
}()
//CAKeyframeAnimation 关键帧1
lazy var keyframeAnimation_1: CAKeyframeAnimation = {
let ani = CAKeyframeAnimation(keyPath: "transform.rotation")
//重复次数
ani.repeatCount = 1
//动画时长
ani.duration = 0.5
//设置动画的关键点
ani.values = [0.0,-Double.pi/4,0.0,Double.pi/4,0.0]
//设置动画关键点对应的时间
ani.keyTimes = [0.0,0.25,0.5,0.75,1]
ani.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
//指定keyframe如果计算中间值
ani.calculationMode = .linear
//对象沿指定path运动过程中, 绕切线旋转模式
ani.rotationMode = nil;
return ani
}()
//CAKeyframeAnimation 关键帧2
lazy var keyframeAnimation_2: CAKeyframeAnimation = {
let ani = CAKeyframeAnimation(keyPath: "position")
ani.repeatCount = 2
ani.duration = 3
ani.values = [CGPoint(x: 0, y: 0)
,CGPoint(x: 100,y: 100)
,CGPoint(x: 100, y: 200)
,CGPoint(x: 150, y: 150)
,CGPoint(x: 100, y: 100)
,CGPoint(x: 0, y: 0)].map({NSValue(cgPoint: $0)})
ani.keyTimes = [0.0,0.2,0.4,0.6,0.8,1]
return ani
}()
//CATransition 提供layer状态切换的动画
lazy var transitionAnimation: CATransition = {
let ani = CATransition.init()
//指定动画起点处于transition的百分比 0.0-1.0 默认0.0
ani.startProgress = 0.5
//指定动画终点处于transition的百分比 0.0-1.0 默认1.0 endProgress>startProgress
ani.endProgress = 1
//type 属性 与 filter 属性冲突。 以filter 为主
//淡入淡出
ani.type = .fade
//图层内容在现有内容之上滑入 ⚠️需要和subType一起使用
// ani.type = .moveIn
// 图层内容推动着现有内容进入 ⚠️需要和subType一起使用
ani.type = .push
//图层内容根据subType指定方向逐渐显示
ani.type = .reveal
//指定transition方向 ⚠️属性 与 filter 属性冲突。 以filter 为主
ani.subtype = nil;
// 从图层底部开始
ani.subtype = .fromBottom
// 从图层左部开始
ani.subtype = .fromLeft
// 从图层右部开始
ani.subtype = .fromRight
// 从图层头部开始
ani.subtype = .fromTop
//mac才可使用
// ani.filter =
ani.duration = 2
ani.isRemovedOnCompletion = true
return ani
}()
//CASpringAnimation 弹簧动画
lazy var springAnimation: CASpringAnimation = {
let ani = CASpringAnimation(keyPath: "position")
//抑制弹簧运动的摩擦力的大小 值变小,弹簧次数增加
ani.damping = 50
//摩擦力变小,settlingDuration 可能大于duration ()
// ani.settlingDuration = 15
//运动时长
ani.duration = 5
// 初始速度
ani.initialVelocity = 5
//挂在弹簧末端的重量, 数值越大 次数越多,幅度越大 settlingDuration也会变大
ani.mass = 10
//弹簧刚性系数
ani.stiffness = 1000
ani.repeatCount = 2
ani.isRemovedOnCompletion = true
ani.fillMode = .forwards
ani.fromValue = NSValue(cgPoint: CGPoint(x: 100, y: 100))
ani.toValue = NSValue(cgPoint: CGPoint(x: 100, y: 500))
ani.delegate = self
return ani
}()
lazy var groupAnimation: CAAnimationGroup = {
let ani_group = CAAnimationGroup()
//添加动画
ani_group.animations = [springAnimation, keyframeAnimation_1]
//动画时长 依此为主
ani_group.duration = 15
//动画开始时间
ani_group.beginTime = CACurrentMediaTime() + 1
ani_group.delegate = self
return ani_group
}()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
fileprivate lazy var backgroundView = {
let view = UIView.init()
view.backgroundColor = UIColor.red
return view
}()
}
extension EYLayerViewController: CAAnimationDelegate{
func animationDidStart(_ anim: CAAnimation) {
}
//flag :到达duration时间 = true , 未到达duration时间 = false
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
}
}
extension EYLayerViewController: CALayerDelegate{
}
05-19
2421
