详解CATransformLayer
详解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的更多相关文章
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- Node.js npm 详解
一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...
随机推荐
- Debugging Ruby in VS Code
原文 https://dev.to/dnamsons/ruby-debugging-in-vscode-3bkj https://github.com/Microsoft/vscode-recipe ...
- InterView之C/CPP cal
cal #define DOUBLE(x) x+x ,i = 5*DOUBLE(5): i 是多少? i 为30. 5 * 5 + 5 下面关于"联合"的题目的输出? A // / ...
- Mozilla新特性只支持https网站,再次推动SSL证书普及
Mozilla的官方博客2015.4.30正式宣布了淘汰HTTP的方案. 其中包括:设定一个日期,所有的新特性将只提供给HTTPS网站:HTTP网站将逐步被禁止访问浏览器功能,尤其是那些与用户安全和隐 ...
- PgAdmin4连接数据库报错:Unable to connect to server: ERROR: unrecognized configuration parameter "bytea_output"
原因: PgAdmin 4不再支持PostgreSQL 9.0 和更早的版本 我的版本是8.2.15 template1=# select version(); version ----------- ...
- Android studio应用导入源码错误This attribute must be localized
This attribute must be localized 产生原因: 多语言错误,源码中关于语言的显示不能直接赋值,而是需要通过xml来实现: 例如 <TextView android: ...
- 使用 Angular 和 RxJS 实现的无限滚动加载
无限滚动加载应该是怎样的? 无限滚动加载列表在用户将页面滚动到指定位置后会异步加载数据.这是避免寻主动加载(每次都需要用户去点击)的好方法,而且它能真正保持应用的性能.同时它还是降低带宽和增强用户体验 ...
- Swift函数_默认参数
swift中提供了默认参数功能,在声明函数时给参数指定默认值. 例: func inputStudentInfo(name:String,age:Int="26") { print ...
- g2o error2
./pose_estimation_3d2d: error while loading shared libraries: libg2o_core.so: cannot open shared obj ...
- java多线程(一)-五种线程创建方式
简单使用示例 Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 还有 定时器 线程池 下 ...
- 自定义Jquery插件——由于项目需要,对页面中过长的文本进行截取,鼠标移上去有一个title的提示,所以做了一个Jquery过长文本处理的插件
由于项目需要,对页面中过长的文本进行截取,鼠标移上去有一个title的提示,所以做了一个Jquery过长文本处理的插件下面是代码: // 掉用方式支持 $('select').textBeauty(1 ...