详解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. hibernate_SessionFactory_getCurrentSession_JTA简介

    JTA:java transaction  api java里所规定的一种管理事务的API 在另一篇播客我写到了,SessionFactory需要关注两个方法, 即:  openSession     ...

  2. yii 页面加载完成后弹出模态框

    <?php $js = <<<JS $('#page-modal').modal('show');//页面加载完显示模态框 $('.modal-dialog').css('wi ...

  3. Java jxl导入excel文件,导入的数字、身份证号码、手机号变成了科学计数法,解决方案

    原文出自:https://blog.csdn.net/seesun2012 这是一个execl文件导入数据库操作,使用jxl解析execl导入数据库过程出现了科学计数法,与想要导入的数据不匹配,以下是 ...

  4. jquery datatables 学习笔记

    最近项目中用到了BootStrap做后台,在选择表格插件的时候发现了jquery datatables. 功能是很强大,但是网上的例子比较少.在经过一段时间的努力可算是搞出来了. 官网地址:http: ...

  5. 在Ubuntu16.04.4和Windows10上安装jdk

    在Ubuntu16.04.4和Windows10上安装jdk 一.在Ubuntu16.04.4上安装jdk  1.下载jdk安装包     首先我们在oracle官网上下载jdk-8u161-linu ...

  6. Apache Rewrite的主要功能

    #Apache Rewrite的主要功能 #就是实现URL的跳转和隐藏真实地址,基于Perl语言的正则表达式规范.#平时帮助我们实现拟静态,拟目录,域名跳转,防止盗链等 在httpd.conf中去掉下 ...

  7. HDU 2553(N皇后)(DFS)

    http://acm.hdu.edu.cn/showproblem.php?pid=2553 i表示行,map[i]表示列,然后用DFS遍历回溯 可以参考这篇文章: http://blog.csdn. ...

  8. 原型链继承中的prototype、__proto__和constructor的关系

    前不久写了有关原型链中prototype.__proto__和constructor的关系的理解,这篇文章说说在原型链继承中的prototype.__proto__和constructor的关系. 通 ...

  9. 13 Reasons Why You Should Pay Attention to Mobile Web Performance

    Mobile is no longer on the sidelines. If you’re not already thinking mobile first, you should at lea ...

  10. git revert后导致合并代码丢失

    起因 我有一个开发分支antd3.x和一个主分支develop,我在合并antd3.x到develop的时候发现有些修改没有合并进来. 查找问题 然后就去网上查,发现这篇文章<git合并丢失代码 ...