简答电子商务网站建设流程,梧州网页设计,网站一个页面多少钱,网站ui标准文章目录简述CALayer简述形状与边框背景与透明度阴影效果遮罩基础的动画CABasicAnimation平行层级关系CGAffineTransform平移#xff0c;旋转~~#xff0c;轴对称~~缩放CATransform3D参考文献“嗯#xff0c;圆和椭圆还不错#xff0c;但如果是带圆角的矩形呢#xff1f;我…
文章目录简述CALayer简述形状与边框背景与透明度阴影效果遮罩基础的动画CABasicAnimation平行层级关系CGAffineTransform平移旋转~~轴对称~~缩放CATransform3D参考文献“嗯圆和椭圆还不错但如果是带圆角的矩形呢我们现在能做到那样了么”
史蒂芬·乔布斯
摘录来自 ios核心动画高级技巧 此材料受版权保护。
简述
核心动画的名字虽然叫核心动画但实际上做动画这只是核心动画的一角
核心动画的存在不是为了替代View而是与View集成提供更好的性能和动画效果 核心动画通过将View缓存为位图让GPU可以直接管理
核心动画的架构如下
比较重要的分支有两个
一个是CAAnimation的动画分支
更重要的是CALayer的图形分支 CALayer中有巨量的专用图层可以实现复杂的效果
CALayer简述
CALayer在与UIView 很像都有层级关系都可以填充文本颜色图片关键在于CALayer 不可以响应用户交互事件单一职责原则
与UIView的关系 每一个UIView 都有layer叫做backing layer UIView 的职责在于管理创建这个CALayer 确保我们可以显示视图
同时可以使用layer来对view进行一些美化操作
这里介绍一些属性
形状与边框 cornerRadius让视图的四个角变得圆润。这个属性非常常用可以用来制作卡片、圆形头像等效果 // 设置圆角半径为 8
myView.layer.cornerRadius 8.0;
// 如果要让视图变成圆形将半径设置为视图宽度的一半
myView.layer.cornerRadius myView.frame.size.width / 2.0;borderWidth设置边框的宽度 // 设置边框宽度为 2 点
myView.layer.borderWidth 2.0;borderColor设置边框的颜色。注意它的类型是 CGColor需要从 UIColor 转换 // 设置边框颜色为蓝色
myView.layer.borderColor [UIColor blueColor].CGColor;背景与透明度 backgroundColor设置图层的背景色。同样需要转换为 CGColor // 设置背景色为红色
myView.layer.backgroundColor [UIColor redColor].CGColor;opacity控制图层的不透明度范围从 0.0完全透明到 1.0完全不透明。常用于实现淡入淡出效果 // 设置透明度为 50%
myView.layer.opacity 0.5;阴影效果
阴影是增加视图立体感和层次感的最佳方式。 shadowColor阴影的颜色通常使用黑色。 myView.layer.shadowColor [UIColor blackColor].CGColor;shadowOpacity阴影的透明度范围从 0.0 到 1.0。如果设置为 0阴影将不可见。 myView.layer.shadowOpacity 0.5;shadowOffset阴影的偏移量。width 控制水平方向height 控制垂直方向。默认是 (0, -3)即向上偏移 // 设置阴影向右下角偏移
myView.layer.shadowOffset CGSizeMake(3, 3);shadowRadius阴影的模糊半径。值越大阴影越柔和 // 设置阴影模糊半径
myView.layer.shadowRadius 5.0;遮罩 masksToBounds一个布尔值决定图层的内容是否被它的边界所裁剪 // 裁剪掉超出边界的内容
myView.layer.masksToBounds YES;基础的动画
核心动画的内部实际上是有巨多巨复杂的概念所以这里我就简单介绍一下动画该怎么显示和使用不会涉及内部的原理之类的
CABasicAnimation
使用animationWithKeyPath 来创建一个基础动画
CABasicAnimation* animation [CABasicAnimation animationWithKeyPath:position.y];对于要修改的属性OC中一般使用字符串来表示如这里的position.y 在获取到实例之后我们就可以编辑这个动画对象了
这里变换的是一个控件的高度
animation.toValue (400);
animation.duration 1;然后把这个动画交给对应视图的layer即可
[self.mainView.glass.layer addAnimation:animation forKey:nil];这里可以看到动画结束后对应的控件又回到了原本的位置这里涉及到一个平行层级关系
平行层级关系
每个UIView有一个CALayer类型的layer属性被称为backing layer。View 负责创建、管理 layer以确保子视图添加、移除时其关联的图层也在相应层级中进行同样操作
屏幕内容的显示和动画都是由 backing layer 负责的UIView仅仅是它的封装提供一些针对 iOS 的功能如响应手势事件和核心动画底层功能的高级封装
为什么 iOS 有两个平行层级的UIView和CALayer 为什么不使用一个层级处理所有事件
同时使用UIView和CALayer是为了职责分离避免代码重复
iOS 和 macOS 中事件和用户交互的处理逻辑有很多不同。多点触摸的触控屏与鼠标、键盘控制的完全不同这也是 iOS 使用UIKit的UIViewmacOS 使用AppKit的NSView的原因它们功能相同但实现方式不同
在 iOS 和 macOS 中都有渲染、布局、动画这些共同概念将这些基础功能独立到 Core Animation框架可以在 iOS、macOS 间共享代码方便 Apple 系统开发人员开发系统以及第三方开发者开发跨平台应用。 实际中这里不是两个平行层级而是四个平行层级各自执行不同功能。层级如下 视图层级View tree图层树Layer tree呈现树Presentation Tree渲染树Render Tree 视图层级 视图层级实际上就是我们在平常创建的UIView对象的层级结构它包含了所有UIView 实例和他们的复制关系 它主要负责处理 用户的交互例如触摸手势点击事件 管理布局负责视图的排列和大小 响应者链管理事件的传递和响应 图层树 每个 UIView 都有一个与之关联的 CALayer 对象。图层树就是这些 CALayer 对象所构成的层级结构。它是视图层级的核心数据模型包含了视图的所有视觉属性如颜色、边框、阴影、三维变换等 它主要负责 存储视觉数据它是CALayer 的真实数据模型存储了所有的可动画属性的最终状态 隐式动画当没有包裹在动画块里时直接修改它的属性会默认出发默认的隐式动画理论上 它定义了视图最终的样子包括颜色形状位置等等所有的视觉细节 呈现树 一个动态副本只在动画执行期间存在反映了所有动画层在每一时刻的实时状态 它负责 提供实时的数据在动画过程中它的属性值会不断的变化提供当前动画的当前帧数据渲染引擎会从呈现树中的数据来绘制屏幕上的每一帧 渲染树 一个核心动画框架内部高度维护的用于渲染的树状结构是一个私有对象一般来说无法直接访问
当我们把动画添加到图层的时候我们并没有改变原本的视图层级中的数据所以在动画执行完毕被移除的时候图层还是会移动到之前的位置
在我们使用CABasicAnimation 来创建动画的前提下更改属性即可让视图变为原来的样子
在代码中加入如下代码
animation.removedOnCompletion NO; // 是否恢复原始状态
animation.fillMode kCAFillModeForwards;
/*
kCAFillModeForwards动画结束后layer会一直保持动画最后的状态
kCAFillModeBackwards:在动画开始的时候只要将动画加入layerlayer便立即进入动画的初始状态第一帧有准备过程并等待动画开始并且保持最后
kCAFillModeBoth上述二者结合
kCAFillModeRemoved对原始的VIew不会有任何的影响默认 */CGAffineTransform
CGAffineTransform是属于Core Graphics框架的绘制二维图像的仿射变换矩阵
常见的坐标变化如下 这里使用CGAffineTransform和之后的CATransform3D实际上是给一个控件的transform属性赋值
这个属性 变化实际上就是系统根据你写的矩阵来对控件的每个点进行运算最后呈现出变化后的图像
CGAffineTransformMakeTranslation 等这类方法实际上制作了一个矩阵输入给控件的属性让他呈现一个变化的效果而已
平移旋转~~轴对称~~
平移使用CGAffineTransformMakeTranslation 方法方法中的两个参数分别应x轴和y轴平移的大小
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform CGAffineTransformMakeTranslation(100, 50);}];NSLog(%,button);NSLog(动画变化);
}效果 旋转使用CGAffineTransformMakeRotation 方法其接受一个弧度制的数值
其中M_PI_2 表示二分之派的大小即90度
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform CGAffineTransformMakeRotation(M_PI_2);}];NSLog(%,button);NSLog(动画变化);
}缩放 缩放使用的方法是CGAffineTransformMakeScale
这里贴出与按钮绑定的方法
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform CGAffineTransformMakeScale(0.8, 0.8);}];NSLog(%,button);NSLog(动画变化);
}这样我们就在点击的过程中让按钮在0.3s第一个参数的时间内将按钮变为原本的0.8倍
由于按钮不会不会自己变回原本的大小所以我们增加一个回调操作
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform CGAffineTransformMakeScale(0.8, 0.8);}completion:^(BOOL finished) {if (finished) {button.transform CGAffineTransformIdentity;}}];NSLog(%,button);NSLog(动画变化);
}但是这样的代码有一个问题在回弹的时候会直接跳转到原本状态
我们在回调里再加入一个动画即可
最终代码和效果如下
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform CGAffineTransformMakeScale(0.8, 0.8);}completion:^(BOOL finished) {if (finished) {[UIView animateWithDuration:0.2 animations:^{button.transform CGAffineTransformIdentity;}];}}];NSLog(%,button);NSLog(动画变化);
}CATransform3D
Core Graphics 是 2D 绘制 APICGAffineTransform只用于 2D 变换。CATransform3D允许在三维空间操控 layer
CATransform3D是个 4*4 矩阵能够对任意点进行 3D 变换 创建CATransform3D简便方法如下
CATransform3DMakeRotation(angle, x, y, z)返回围绕向量(x, y, z) 旋转 angle 弧度的变换CATransform3DMakeScale(sx, sy, sz)返回缩放比例为(sx, sy, sz) 的变换CATransform3DMakeTranslation(tx, ty, tz)返回平移为 (tx, ty, tz) 的变换
我们已经很熟悉x、y轴z 轴垂直于x、y轴并向外延伸 并且对上面的函数基本上的功能也了解所以这里就不多做介绍了
为了便于识别我们加入一张图片作为背景
展示动画代码
// 动画设置
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:0.3 animations:^{button.transform3D CATransform3DMakeRotation(M_PI_4, 0, 1, 0);}];
}观察移动效果可以发现这里的旋转好像并没有立体感
这是因为我们是面向屏幕观看的没有透视perspective为解决此问题还需修改变换矩阵以包含透视变换也称为z变换。CATransform3D的m34控制着透视效果m34的值在变换计算中用于按比例缩放x和y的值其反映了距离视点的距离 m34默认值为0为其赋值 -1.0/d 以添加透视投影d 为设想中视点与屏幕的距离单位为 point
通常500到1000之间会有很好效果有时大值或小值对某些 layer 排布效果更好减少距离可以增加透视效果
因此很小的值看起来会非常失真而很大的值看起来就像根本没有透视
由于我们使用的animation是动态调整数值的方法所以你不能像之前一样直接修改m34
// 动画设置
- (void) pressBtn:(UIButton*)button {[UIView animateWithDuration:2 animations:^{CATransform3D transform CATransform3DIdentity;transform.m34 -1.0 / 500.0;transform CATransform3DRotate(transform, M_PI / 4.0, 0, 1, 0);button.transform3D transform;}];NSLog(%,button);NSLog(动画变化);
}当沿着铁路线去看两条铁轨或者沿着公路线看两遍整齐的树木时其连线相交于很远很远的某一点这点在透视投影中称为消失点vanishing point又称为灭点
在真实世界中消失点一般位于视野的中心。想要在 app 中添加灭点效果灭点应位于屏幕中心或者包含所有 3D 视图的中心在这里简单了解后即可 Core Animation 消失点位于未进行变换的 layer 的anchorPoint处。如果图层添加了平移变换layer 平移到了其他位置anchorPoint仍然位于平移前位置灭点也位于平移前的位置
改变position属性会修改 vanishing point。因此想要修改 layer 的m34属性时应先将 layer 放置于屏幕中心后使用 translation transform 平移 layer 到目标位置这样其可以与其他 3D 图层共享同一个消失点就可以解决立体感出现问题的情况了
参考文献
https://www.bookstack.cn/read/ios_core_animation_advanced_techniques/chapter1-layers-and-trees.mdhttps://www.jianshu.com/p/abf9bde5bd6ahttps://zh.zlibicu.ru/book/17751253/311eb3/ios核心动画高级技巧.html?ts1512https://dev59.com/P2w05IYBdhLWcg3w3lkl【iOS开发-核心动画原理解析底层进阶/面试/跳槽加薪必看iOS开发教程】 https://www.bilibili.com/video/BV1np4y1r714/?p3share_sourcecopy_webvd_sourcefb5d66e534ab71bb9575a728199792ff