Core Animation 学习笔记2 - Layer

包含 CABasicAnimation 的一些简单动画,Spring 后面的再学。

最近开始忙项目了,停较长一段时间


6. Layer

Layer 概述

Layer 是一个简单的对象,只对外提供一些图像显示方面的内容相关的属性,每一个 UIView 背后都有一个 Layer 层。

Layer 跟 UIView 是不一样的,主要因为:

  1. Layer 只是一个简单的模型对象,不像 UIView 那么逻辑对象,没有复杂的自动布局和手势识别等。
  2. Layer 预定义了很多可见的特性,这些特性是一系列的呈现在屏幕上的内容的数据,比如边界线、边框颜色、位置、阴影等。
  3. Core Animation 优化了对 layer 的支持,比如缓存,并且直接使用 GPU 进行绘制。

UIView 之所以复杂,是因为他还负责了 NSAutoLayout 用户交互等复杂的逻辑,但是Layer没有任何逻辑,只是提供了缓存和 GPU 绘制。
所以 UIView 非常灵活机动,有很多的子类,但是 Layer 子类就非常少,层级更加简单。

UIView 任何时候都能胜任工作,但是如果要考虑优化和性能的时候就得考虑 Layer 了。

Core Animation 操作 Layer 同样跟 UIView 一样通过设定起终点的状态以及过度方式来操作,只是在 Layer 中不仅仅可以操作之前的:frame、position、opacity,还有更多属性可以修改。

6.1 Layer 属性

定位与尺寸 position size

  • bounds : 改变layer的边界frame
  • positon : 可以理解成 UIView 的 center,具有 x y 两个属性。
  • transform : Layer 的 transform 还可以 3D 变换,修改 scala, 角度 rotate .

边界 border

  • borderColor : tint 边界颜色
  • borderWidth : 边界宽度
  • borderRadius : 圆角矩形圆角半径

阴影 shadow

  • shadowOffset: 代表阴影跟Layer的偏移
  • shadowOpacity: 修改这个值让阴影渐进渐出
  • shadowPath: 修改 Layer 的阴影的形状
  • shadowRadius: 让阴影变模糊

内容 Contents

最后这些属性控制着最后给 Layer 展示的数据,直接用户看到的一层

  • contents: 修改这个值去分配原生的 TIFF 或 PNG 数据给 Layer 的内容
  • mask: 修改这个值去重建形状跟图像。
  • opacity: 透明度

UIView 的动画不能指定开始状态,但是 Layer 很多情况下可以指定开始状态。

6.2 CABasicAnimation

创建一个 CABasicAnimation 对象:

然后创建一个 CABasicAnimation 对象,然后添加到 view 的 layer 上,keyPath 用来指定动画的属性,上面提到过的属性都可以作为动画目标属性。

    let flyRight = CABasicAnimation(keyPath: "position.x")
    flyRight.fromValue = -view.bounds.size.width/2
    flyRight.toValue = view.bounds.size.width/2
    flyRight.duration = 0.5
    
//把动画添加到 layer 上
    heading.layer.add(flyRight, forKey: nil)

当我们这样创建一个 CABasicAnimation 的时候,flyRight 只是一个对象,它跟任何一个 layer 都没有关系。当 add 方法调用的时候,传入绑定 Layer 的是一个它的 copy,并不是我们创建的这个对象本身。

所以我们可以复用 CABasicAnimation 对象。

fillMode 动画模式

使用动画对象的这个属性,让你控制动画在开始到结束的整个流程出现的状态。

关于 Layer 动画状态的控制,通过 fillMode 变量来控制 layer 起始状态的展示。

用动画开始和结束来分割一个 Layer 的时间线,可以分为三个区域,动画开始前,动画中,以及动画结束后,fillMode 的四个值,包括了动画的四种前后帧的留存情况。

通过设置 动画的 fillMode 属性,可以控制动画帧在动画开始之前以及结束之后的停留与否的影响,有四个枚举值:

  • kCAFillModeRemoved : 仅动画期间
  • kCAFillModeBackwards : 以及开始之前
  • kCAFillModeForwards : 以及结束之后
  • kCAFillModeBoth : 包括开始结束

所以当你改变了动画的开始结束时间,应该考虑到 presentation layer 层的留存情况。

比如延迟动画时间:

flyRight.beginTime = CACurrentMediaTime() + 0.3
flyRight.fillMode = kCAFillModeBoth

另一个属性是 isRemovedOnCompletion,这个属性默认值为 true,结束的时候如果要保留 Layer 位置,就要设置为 false。

动画层 与 Layer 层

当执行动画的时候,我们看到的不是真正的 Layer,而是一个 presentation layer,动画执行完毕,展示的 Layer 就会移出视图,然后重新展示原始的 Layer。

展示 Layer 也不接收交互事件的。

CABasicAnimation 有一个属性 isRemoveOnCompletion,这个属性结合上一个 fillMode,设置前者为 false,后者为kCAFillModeBoth,可以在动画结束的时候,把动画最后的一个 Layer 留存下来。

但是尽量避免保留动画的 Layer 层,考虑性能以及手势的问题,当一个动画运行完毕,就移出界面,然后更新 UIView 的属性。

6.2 动画 Keys & Delegate

CAAnimationDelegate

UIKit API 的 UIView 动画只能根据 Closure 进行动画,一旦开始,不能暂停停止或者获取动画对象。

相比之下 CA 动画的机动性就比较强,有获取动画对象、设置代理方法。

CAAnimation 跟 CABasicAnimation 都遵守了代理 CAAnimationDelegate,开始结束的代理方法如下:

extension ViewController: CAAnimationDelegate {
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        print("animation did finish.")
    }

    func animationDidStart(_ anim: CAAnimation) {
        print("Start!")
    }
}

KVC

CAAnimation 基于 OC 实现,所以 KVC KVO 都是可用的。

可以使用 KVC KVO 给 CAAnimation 对象设置 value,存取案例:

    flyRight.setValue("form", forKey: "name")
    flyRight.setValue(heading.layer, forKey: "layer")
    
    //读取
    guard let name = anim.value(forKey: "name") as? String else {
        return
    }

动画 Keys

在给 layer 添加 Animation 的时候,有一个 key 参数,这个参数是用来指定动画的标示,让我们方便获取动画对象,以便甚至在动画运行的时候去控制它。

当多个动画各自独立执行的时候,这些 Key 参数就可以发挥作用了。

执行中的动画

Layer 有一个方法 layer.animationKeys(),获取所有动画的数组

获取动画可以做:

  • 执行 removeAllAnimations() 取消所有动画,或者 removeAnimation(forKey:) 根据 key 取消动画
  • 通过 animationKeys() 遍历动画,获取的都是 immutable 对象,在他们执行的时候并不能进行修改。
  • 获取某一个动画通过 animationForKey(_:),获取的是 immutable 对象

6.3 动画组

多个动画打包成一个动画,多动画的同步,实现动画属性的统一管理。

当多个动画运行在一个 Layer 上面的时候,很多时候我们需要让这些动画相互同步,使用 CAAnimationGroup 可以解决这个问题。表面上只是将多个动画合并,统一处理,背后的动画同步等机制,全部由 CAAnimationGroup 来完成。

实现如下:

//  1️⃣:像正常创建 CABasicAnimation 一样创建 CAAnimationGroup,他们都是继承自 `CAAnimation`,所以属性也有 `beginTime` `duration` `fillMode` `delegate` `isRemoveOnCompletion`。
    let groupAnimation = CAAnimationGroup()
    groupAnimation.beginTime = CACurrentMediaTime()
    groupAnimation.duration = 0.5
    groupAnimation.fillMode = kCAFillModeBackwards
    
//  2️⃣:然后单独创建三个 CABAsicsAnimation
    let scaleDown = CABasicAnimation(keyPath: "transform.scale")
    scaleDown.fromValue = 3.5
    scaleDown.toValue = 1.0
    
    let rotate = CABasicAnimation(keyPath: "transform.rotation")
    rotate.fromValue = .pi/4.0
    rotate.toValue = 0.0
    
    let fade = CABasicAnimation(keyPath: "opacity")
    fade.fromValue = 0.0
    fade.toValue = 1.0
    
//  3️⃣:最后通过对 group 动画设置动画数组的方法,分开的动画打成动画组,通过设置 groupAnimation 对象的 animations 属性,然后调用 layer 的 add 方法
    groupAnimation.animations = [scaleDown, rotate, fade]
    loginButton.layer.add(groupAnimation, forKey: nil)

但是说什么动画可以打包,什么动画需要独立编写,需要自己通过经验去衡量把握。比如一个启动界面的 ViewDidAppear 里面的动画,在刚进入界面的时候开始,还是应该打成组的。

慢入慢出 EaseInOut

EaseInOut 在 UIView 的动画中通过设置调用 UIView 的 animate 方法中的 options 参数配置。

在 Layer 中也比较类似,只是语法上有一些区别,通过设置 Animation 对象的 timingFunction 属性来实现,这个属性是一 CAMediaTimingFunction 对象,继承自 NSObject, 通过初始化方法指定 name 参数为一下四个预定义的值,即可创建预定义好的慢入慢出对象。

CAMediaTimingFunction 初始化方法的四个预定义 name 的值:

  • kCAMediaTimingFunctionLinear
  • kCAMediaTimingFunctionEaseIn
  • kCAMediaTimingFunctionEaseOut
  • kCAMediaTimingFunctionEaseInEaseOut

这四个函数跟前面 UIView 的慢入慢出类似,第一个是正常,第二个是慢入,第三个慢出,第四个慢入慢出。

慢如慢出动画的执行阶段
    groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)

我们可以创建自定义的 CAMediaTimingFunction 对象,通过 init 方法 controlPoints,传入四个贝赛尔曲线的两个控制点的坐标,即可以实现,不赘述。

动画重复 RepeatCount

设置动画的重复次数,即结束之后,重复从头开始动画,通过设置 CABasicAnimation 的属性 repeatCount,设置重复的次数。

另外的一个属性 autoreverses,设置自动逆向播放,动画完成之后,再逆向动画一次。

通过同时设置这两个参数,可以时间循环逆向播放动画。一轮正逆算 repeat 一次。

如果设置动画对象的 repeatCount 为 1.5,则动画的第二次动画的逆向动画取消,第二次只播放一次正向动画。

动画速度 speed

CABasicAnimation 的参数 speed,可以控制动画的速度,默认值为 1.0f。

其实:

动画的实际消耗时间 * speed = duration

单独设置 CABasicAnimation 对象的 speed 之外,还可以直接设置 Layer 的 speed,比如设置 self.view.layer.speed = 2.0,viewController 的 view 之下的所有动画都会以 2.0 的速度播放。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 在iOS实际开发中常用的动画无非是以下四种:UIView动画,核心动画,帧动画,自定义转场动画。 1.UIView...
    请叫我周小帅阅读 3,082评论 1 23
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,104评论 5 13
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,471评论 6 30
  • 目录1. Core Animation 核心动画简介2. CABasicAnimation3. CAKeyfram...
    云中追月阅读 457评论 0 4
  • 单选题B 2.C 3.B 4.D 5.B 6.B 7.B 8.C 9.B 10.A 11.D 12.A 13.A ...
    An九儿阅读 354评论 0 0