详解CATransformLayer

CATransformLayer与CALayer有着细微的差别,但这些差别会影响到3D变换的动画效果.

动画都有坐标系,如下所示(注意,这个不是iOS中的坐标系,请勿对号入座):

iOS中layer的锚点就在坐标系的正中间.

layer的position可以理解为View的center.

实现带有3d景深效果动画:

//
// RootViewController.m
// CATransformLayer
//
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import "RootViewController.h"
#import "YXGCD.h" @interface RootViewController ()
@property (nonatomic, strong) GCDTimer *timer;
@end @implementation RootViewController #define V_CENTER_X self.view.center.x
#define V_CENTER_Y self.view.center.y
#define CG_COLOR(R, G, B, A) [UIColor colorWithRed:(R) green:(G) blue:(B) alpha:(A)].CGColor
#define DEGREE(d) ((d) * M_PI / 180.0f) - (void)viewDidLoad
{
[super viewDidLoad]; // 普通的一个layer
CALayer *plane = [CALayer layer];
plane.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane.position = CGPointMake(V_CENTER_X, V_CENTER_Y); // 位置
plane.opacity = 0.6; // 背景透明度
plane.backgroundColor = CG_COLOR(, , , ); // 背景色
plane.borderWidth = ; // 边框宽度
plane.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane.cornerRadius = ; // 圆角值 // 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
[container addSublayer:plane]; // 启动定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
static float degree = .f; // 起始值
CATransform3D fromValue = CATransform3DIdentity;
fromValue.m34 = 1.0/ -;
fromValue = CATransform3DRotate(fromValue, degree, , , ); // 结束值
CATransform3D toValue = CATransform3DIdentity;
toValue.m34 = 1.0/ -;
toValue = CATransform3DRotate(toValue, degree += .f, , , ); // 添加3d动画
CABasicAnimation *transform3D = [CABasicAnimation animationWithKeyPath:@"transform"];
transform3D.duration = .f;
transform3D.fromValue = [NSValue valueWithCATransform3D:fromValue];
transform3D.toValue = [NSValue valueWithCATransform3D:toValue];
plane.transform = toValue;
[plane addAnimation:transform3D forKey:@"transform3D"]; } timeInterval:NSEC_PER_SEC];
[_timer start];
} @end

下图中的m34值代表着景深效果,非常关键,其值越接近0,景深效果就越发强烈

如果写成这样子:

那么显示就会变成:

毫无3d感可言.

将景深效果添加到容器上面去我们就能得到如下的效果:

- (void)viewDidLoad
{
[super viewDidLoad]; // 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane1.position = CGPointMake(, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(, , , ); // 背景色
plane1.borderWidth = ; // 边框宽度
plane1.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = ; // 圆角值 // 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane2.position = CGPointMake( + , V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(, , , ); // 背景色
plane2.borderWidth = ; // 边框宽度
plane2.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = ; // 圆角值 // 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container]; CATransform3D plane_3D = CATransform3DIdentity;
plane_3D.m34 = 1.0/ -;
plane_3D = CATransform3DRotate(plane_3D, DEGREE(), , , );
container.transform = plane_3D; [container addSublayer:plane1];
[container addSublayer:plane2];
}

注意,下图红框中的值是非常关键的哦:

到这里还没讲CATransformLayer呢,先看个例子:

效果如下:

- (void)viewDidLoad
{
[super viewDidLoad]; // 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane1.position = CGPointMake(, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(, , , ); // 背景色
plane1.borderWidth = ; // 边框宽度
plane1.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = ; // 圆角值 // Z轴平移
CATransform3D plane1_3D = CATransform3DIdentity;
plane1_3D = CATransform3DTranslate(plane1_3D, , , -);
plane1.transform = plane1_3D; // 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane2.position = CGPointMake(, V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(, , , ); // 背景色
plane2.borderWidth = ; // 边框宽度
plane2.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = ; // 圆角值 // Z轴平移
CATransform3D plane2_3D = CATransform3DIdentity;
plane2_3D = CATransform3DTranslate(plane2_3D, , , -);
plane2.transform = plane2_3D; // 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container]; // 以Y轴为坐标系,旋转45度
CATransform3D t = CATransform3DIdentity;
t.m34 = 1.0/-;
t = CATransform3DRotate(t, DEGREE(), , , );
container.transform = t; [container addSublayer:plane1];
[container addSublayer:plane2];
}

如果把上图的CALayer替换成下图的CATransformLayer

则会产生如下的效果:

看到上面的图,你应该就明白了CATransformLayer当做容器是为了给里面的Layer提供景深效果用的.

再来做成动画看看效果吧:

- (void)viewDidLoad
{
[super viewDidLoad]; // 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane1.position = CGPointMake(, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(, , , ); // 背景色
plane1.borderWidth = ; // 边框宽度
plane1.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = ; // 圆角值 // Z轴平移
CATransform3D plane1_3D = CATransform3DIdentity;
plane1_3D = CATransform3DTranslate(plane1_3D, , , -);
plane1.transform = plane1_3D; // 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(, )}; // 尺寸
plane2.position = CGPointMake(, V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(, , , ); // 背景色
plane2.borderWidth = ; // 边框宽度
plane2.borderColor = CG_COLOR(, , , 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = ; // 圆角值 // Z轴平移
CATransform3D plane2_3D = CATransform3DIdentity;
plane2_3D = CATransform3DTranslate(plane2_3D, , , -);
plane2.transform = plane2_3D; // 创建容器layer
CATransformLayer *container = [CATransformLayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
[container addSublayer:plane1];
[container addSublayer:plane2]; // 启动定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
static float degree = .f; // 起始值
CATransform3D fromValue = CATransform3DIdentity;
fromValue.m34 = 1.0/ -;
fromValue = CATransform3DRotate(fromValue, degree, , , ); // 结束值
CATransform3D toValue = CATransform3DIdentity;
toValue.m34 = 1.0/ -;
toValue = CATransform3DRotate(toValue, degree += .f, , , ); // 添加3d动画
CABasicAnimation *transform3D = [CABasicAnimation animationWithKeyPath:@"transform"];
transform3D.duration = .f;
transform3D.fromValue = [NSValue valueWithCATransform3D:fromValue];
transform3D.toValue = [NSValue valueWithCATransform3D:toValue];
container.transform = toValue;
[container addAnimation:transform3D forKey:@"transform3D"]; } timeInterval:NSEC_PER_SEC];
[_timer start];
}

详解CATransformLayer的更多相关文章

  1. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  2. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  3. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  4. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  5. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  6. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  7. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  8. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

  9. Node.js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

随机推荐

  1. easyui的datagrid对应的java对象

    Easyui中datagrid控件要求的数据格式为: {total:”2”,rows:[{“id”:”1”,”name”,”张三”},{“id”:”2”,”name”,”李四”}]} 所以可以建一个对 ...

  2. 17.Generator函数的异步应用

    异步编程对 JavaScript 语言太重要.Javascript 语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可. 1.传统方法 ES6 诞生以前,异步编程的方法,大概有下面 ...

  3. 我爱Markdown (3)

    继续Markdown的常见语法, 本文将介绍: 07 - Links 链接 08 - Images 图片 09 - Blockquotes 块引用 10 - Backslash Escapes 显示保 ...

  4. C++11 并发(一道笔试题目)

    题目:编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. #include < ...

  5. QT下载地址大全

    1. 所有Qt版本下载地址: http://download.qt.io/archive/qt/ 2. 所有Qt Creator下载地址: http://download.qt.io/archive/ ...

  6. 【转】winform程序textbox滚动条保持在最下面 内容不闪烁

    在开发winform程序时,会用到textbox控件来显示信息,当把textbox的Multiline属性改为Ture时(即多行显示状态),ScrollBars属性改为Vertical(内容过多时,显 ...

  7. webstorm软件小技巧

    1.使用tab可以方便的生成代码片段 调出setting,搜索live template 在javascrpt 模板线面点击"+" 添加一个模板 fun 模板内容如下 functi ...

  8. javascript的ajax功能的概念和示例

    AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML). 个人理解:ajax就是无刷新提交,然后得到返回内容. 对应的不使用ajax时的传统网 ...

  9. Vue学习笔记:编译过程

    碰到是否有template选项时,会询问是否要对template进行编译: 在template编译(渲染成UI)有一个过程.模板通过编译生成AST,再由AST生成Vue的渲染函数,渲染函数结合数据生成 ...

  10. Spring MVC 实现Excel的导入导出功能(2:Excel的导入优化和Excel的导出)

    Excel的导入V2优化版 有些时候文件上传这一步骤由前端来处理,只将上传后的 URL 传输给后端(可以参考上一文中的图片上传功能),也就是导入请求中并不会直接处理 MultipartFile 对象, ...