第五章:Transforms

 
Affine Transforms
 
CGAffineTransform是二维的
 
 
Creating a CGAffineTransform
 
主要有三种变化方法
旋转:
CGAffineTransformMakeRotation(CGFloat angle)
 
 
缩放:
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
 
移动:
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
 
 
 

例子5.1 CGAffineTransformMakeRotation

源码在这里下载:http://www.informit.com/title/9780133440751

  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *layerView;
  3. @end
  4. @implementation ViewController
  5. - (void)viewDidLoad
  6. {
  7. [super viewDidLoad];
  8. //rotate the layer 45 degrees
  9. CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
  10. self.layerView.layer.affineTransform = transform;
  11. }
  12. @end

 
修改 CGAffineTransformMakeScale
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //rotate the layer 45 degrees
  5. CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);
  6. self.layerView.layer.affineTransform = transform;
  7. }

修改   CGAffineTransformMakeTranslation
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //rotate the layer 45 degrees
  5. CGAffineTransform transform = CGAffineTransformMakeTranslation(-50.0, 30.0);
  6. self.layerView.layer.affineTransform = transform;
  7. }

 
 
 
Combining Transforms
 
方法1:使用CGAffineTransformConcat
 
继续修改例子5.1
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //rotate the layer 45 degrees
  5. CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI_4);
  6. CGAffineTransform transform2 = CGAffineTransformMakeScale(0.5, 0.5);
  7. CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
  8. self.layerView.layer.affineTransform = transform;
  9. }

 
方法2:
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
和前面的CGAffineTransformMakeRotation函数相同,也可以混用
CGAffineTransform t可以使用CGAffineTransformIdentity函数初始化
 
例子5.2
  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *layerView;
  3. @end
  4. @implementation ViewController
  5. - (void)viewDidLoad
  6. {
  7. [super viewDidLoad];
  8. //create a new transform
  9. CGAffineTransform transform = CGAffineTransformIdentity;
  10. //scale by 50%
  11. transform = CGAffineTransformScale(transform, 0.5, 0.5);
  12. //rotate by 30 degrees
  13. transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
  14. //translate by 200 points
  15. transform = CGAffineTransformTranslate(transform, 200, 0);
  16. //apply transform to layer
  17. self.layerView.layer.affineTransform = transform;
  18. }
  19. @end

 
 
下面记几个特殊值
1. 首先要知道函数 CGAffineTransformIdentity 初始化的结果
          
 
2. 左右翻转
    CGAffineTransformMake(-1,0,0,1,0,0);

 
3. 以右边为轴向右翻转
    CGAffineTransformMake(-1,0,0,1,self.layerView.frame.size.width,0);
 

4. 上下翻转

CGAffineTransformMake(1,0,0, -1,0,0);

 
5. 以底边为轴向下翻转
    CGAffineTransformMake(1,0,0, -1,0,self.layerView.frame.size.height);
 
6. 转180°
    CGAffineTransformMake(-1,0,0, -1,0,0);
 
7. 例子5.3,向右斜拉
    CGAffineTransformMake(1,0, -1,1,0,0);
代码:
  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *layerView;
  3. @end
  4. @implementation ViewController
  5. CGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y)
  6. {
  7. CGAffineTransform transform = CGAffineTransformIdentity;
  8. transform.c = -x;
  9. transform.b = y;
  10. return transform;
  11. }
  12. - (void)viewDidLoad
  13. {
  14. [super viewDidLoad];
  15. //shear the layer at a 45-degree angle
  16. self.layerView.layer.affineTransform = CGAffineTransformMakeShear(1, 0);
  17. }
  18. @end

 
8. 例子5.3,向左斜拉

    CGAffineTransformMake(1, 0,1, 1, 0, 0);
 
 
 
3D Transforms
 
类似CGAffineTransform,CATransform3D是三维的
 

CATransform3D又是一个结构。他有自己的一个公式,可以进行套用。

struct CATransform3D

{

CGFloat     m11(x缩放),    m12(y切变),    m13(旋转),     m14( );

CGFloat     m21(x切变),    m22(y缩放),    m23( ),           m24( );

CGFloat     m31(旋转),      m32( ),           m33( ),            m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);

CGFloat     m41(x平移),    m42(y平移),    m43(z平移),    m44( );

};

 
同样有三种变换方法
 
旋转:
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
首先要先清楚x,y,z是什么
{x, y, z}组成的向量就是旋转要使用的轴,angle是旋转角度
 

例:原图

向X轴旋转45度。                               向Y轴旋转45度。                         向Z轴旋转45度。

    

向 X轴,Y轴都旋转45度,就是沿着对角线旋转。

 
 
缩放:
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)

sx:X轴缩放,代表一个缩放比例,一般都是0 ---1之间的数字。

sy:Y轴缩放。

sz:整体比例变换时,也就是m11(sx) == m22(sy)时,若m33(sz)>1,图形整体缩小,

若0 < m33(sz) < 1,图形整体放大,

若m33(sz) < 0,发生关于原点的对称等比变换。

 

当sx = 1,sy =1时。如图:

当sx = 0.5,sy =0.5时。如图:

 
 
变换:
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]

1    0    0    0

0    1    0    0

0    0    1    0

tx   ty    tz   1

竖起来看对应前面的数据结构就很明显了。

tx:X轴偏移位置,往下为正数。

ty:Y轴偏移位置,往右为正数。

tz:Z轴偏移位置,往外为正数。

 

可以通过直接修改数据结构,来设置变换效果

struct CATransform3D

{

CGFloat m11, m12, m13, m14;

CGFloat m21, m22, m23, m24;

CGFloat m31, m32, m33, m34;

CGFloat m41, m42, m43, m44;

}

  1. CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
  2. transform.m11 = 2;

或者修改键值

  1. [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];
 

 
例子5.4
  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *layerView;
  3. @end
  4. @implementation ViewController
  5. - (void)viewDidLoad
  6. {
  7. [super viewDidLoad];
  8. //rotate the layer 45 degrees along the Y axis
  9. CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
  10. self.layerView.layer.transform = transform;
  11. }
  12. @end

 
修改例子5.4,修改自http://lepetit-prince.net/ios/?p=451
 
  1. #import "ViewController.h"
  2. #import <QuartzCore/QuartzCore.h>
  3. @interface ViewController ()
  4. {
  5. BOOL front;
  6. }
  7. @property (nonatomic, weak) IBOutlet UIView *layerView;
  8. @end
  9. @implementation ViewController
  10. - (void)viewDidLoad
  11. {
  12. [super viewDidLoad];
  13. front = YES;
  14. self.layerView.layer.contents = (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);
  15. }
  16. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  17. {
  18. [UIView animateWithDuration:0.5 animations:^{
  19. self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 0.5, 0.0f, 1.0f, 0.0f);
  20. } completion:^(BOOL finished) {
  21. self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 1.5, 0.0f, 1.0f, 0.0f);
  22. self.layerView.layer.contents = front ? (__bridge id)([UIImage imageNamed:@"back.png"].CGImage) : (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);
  23. [UIView animateWithDuration:0.5 animations:^{
  24. self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 2, 0.0f, 1.0f, 0.0f);
  25. } completion:^(BOOL finished) {
  26. front = !front;
  27. }];
  28. }];
  29. }
  30. @end

资源文件 front.png   back.png

 
 
Perspective Projection
 
前面提到过m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义)
 
例子5.5
  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *layerView;
  3. @end
  4. @implementation ViewController
  5. - (void)viewDidLoad
  6. {
  7. [super viewDidLoad];
  8. //create a new transform
  9. CATransform3D transform = CATransform3DIdentity;
  10. //apply perspective
  11. transform.m34 = - 1.0 / 500.0;
  12. //rotate by 45 degrees along the Y axis
  13. transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
  14. //apply to layer
  15. self.layerView.layer.transform = transform;
  16. }
  17. @end

 
如果修改注释掉旋转,看看会有什么结果
  1. //rotate by 45 degrees along the Y axis
  2. //transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);

例子是用的透视场景是±1.0/d,d镜头到景物的距离,取值500~1000效果最好,±代表方向

 
 
The Vanishing Point
 
当景物慢慢远离镜头时,随着越来越小最终聚集到一点就是Vanishing Point(灭点)
 
通常情况灭点是在视图的正中心,或者在包含所有景物范围的中心。
 
Core Animation把灭点定义在anchorPoint,所以在变换前需要确定anchorPoint,
尤其需要注意,3D变换时最好确保同一视图内的所有layey有相同的灭点
 
 
The sublayerTransform Property
 
如果你有多个View或Layer有相同的3D变换,就可以使用sublayerTransform,

sublayerTransform也是CATransform3D,只有sublayers才会响应。

默认值是Identity Transform(CATransform3DIdentity)

例子5.6
  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *containerView;
  3. @property (nonatomic, weak) IBOutlet UIView *layerView1;
  4. @property (nonatomic, weak) IBOutlet UIView *layerView2;
  5. @end
  6. @implementation ViewController
  7. - (void)viewDidLoad
  8. {
  9. [super viewDidLoad];
  10. //apply perspective transform to container
  11. CATransform3D perspective = CATransform3DIdentity;
  12. perspective.m34 = - 1.0 / 500.0;
  13. self.containerView.layer.sublayerTransform = perspective;
  14. //rotate layerView1 by 45 degrees along the Y axis
  15. CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
  16. self.layerView1.layer.transform = transform1;
  17. //rotate layerView2 by 45 degrees along the Y axis
  18. CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
  19. self.layerView2.layer.transform = transform2;
  20. }
  21. @end

我们挪动一下xib里的图片位置:
再看结果
 
恢复xib文件,并修改代码
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //apply perspective transform to container
  5. //    CATransform3D perspective = CATransform3DIdentity;
  6. //    perspective.m34 = - 1.0 / 500.0;
  7. //    self.containerView.layer.sublayerTransform = perspective;
  8. //apply perspective
  9. CATransform3D transform1 = CATransform3DIdentity;
  10. transform1.m34 = - 1.0 / 500.0;
  11. transform1 = CATransform3DRotate(transform1, M_PI_4, 0, 1, 0);
  12. self.layerView1.layer.transform = transform1;
  13. //rotate layerView2 by 45 degrees along the Y axis
  14. CATransform3D transform2 = CATransform3DIdentity;
  15. transform2.m34 = - 1.0 / 500.0;
  16. transform2 = CATransform3DRotate(transform2, -M_PI_4, 0, 1, 0);
  17. self.layerView2.layer.transform = transform2;
  18. }

结果和最初一样,但再次修改xib文件,挪动图片看结果,比较未改代码时的效果
 
 
大家发现设置sublayerTransform的好处了吗
 
1. 可以一次设置所有subLayer的变换效果
2. Vanishing Point(灭点)被同时设置在container layer即父图层的中心,这就意味着无论你怎么
    修改subLayer的position或frame,它们都会保持一个相同的灭点。
 
 
Backfaces
 
例子5.4,我们设置的是旋转M_PI_4(45°),改为M_PI(180°)
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //rotate the layer 45 degrees along the Y axis
  5. CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
  6. self.layerView.layer.transform = transform;
  7. }

 
翻到了layer背面,显示的是原图像的镜像图。由此可见layer是双面的,并且两面都被描绘了。
因此我们会想到,为什么要浪费GPU去描绘我们看不见的部分呢。CALayer的另外一个属性
doubleSided可以解决这个问题。
在刚才修改过的例子5.4的代码中增加doubleSided设置
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //rotate the layer 45 degrees along the Y axis
  5. CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
  6. self.layerView.layer.transform = transform;
  7. self.layerView.layer.doubleSided = NO;
  8. }


图像没有了

 
 
 
 
Layer Flattening
自己看例子吧,例子5.7和5.8
 
 
Solid Objects
也自己看例子吧,例子5.9和5.10

IOS Core Animation Advanced Techniques的学习笔记(四)的更多相关文章

  1. IOS Core Animation Advanced Techniques的学习笔记(一)

    转载. Book Description Publication Date: August 12, 2013 Core Animation is the technology underlying A ...

  2. IOS Core Animation Advanced Techniques的学习笔记(五)

    第六章:Specialized Layers   类别 用途 CAEmitterLayer 用于实现基于Core Animation粒子发射系统.发射器层对象控制粒子的生成和起源 CAGradient ...

  3. IOS Core Animation Advanced Techniques的学习笔记(二)

    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { CGFloat width = 10.0f; //draw a thi ...

  4. IOS Core Animation Advanced Techniques的学习笔记(三)

    第四章:Visual Effects   Rounded Corners 例子4.1 cornerRadius 源码在这里下载:http://www.informit.com/title/978013 ...

  5. iOS Core Animation Advanced Techniques

    Book Descripter Core Animation is the technology underlying Apple's iOS user interface. By unleashin ...

  6. 转 iOS Core Animation 动画 入门学习(一)基础

    iOS Core Animation 动画 入门学习(一)基础 reference:https://developer.apple.com/library/ios/documentation/Coco ...

  7. iOS Core Animation 简明系列教程

    iOS Core Animation 简明系列教程  看到无数的CA教程,都非常的难懂,各种事务各种图层关系看的人头大.自己就想用通俗的语言翻译给大家听,尽可能准确表达,如果哪里有问题,请您指出我会尽 ...

  8. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  9. iOS - Core Animation 核心动画

    1.UIView 动画 具体讲解见 iOS - UIView 动画 2.UIImageView 动画 具体讲解见 iOS - UIImageView 动画 3.CADisplayLink 定时器 具体 ...

随机推荐

  1. 【leetcode❤python】 189. Rotate Array

    #-*- coding: UTF-8 -*-#由于题目要求不返回任何值,修改原始列表,#因此不能直接将新生成的结果赋值给nums,这样只是将变量指向新的列表,原列表并没有修改.#需要将新生成的结果赋予 ...

  2. php set_time_limit()用法测试详解

    在php中set_time_limit函数是用来限制页面执行时间的,如我想把一个php页面的执行时间定义为5秒就可以set_time_limit(5)了.   一个php脚本通过crontab每5分钟 ...

  3. 一个div里有多个a标签,改变a标签的字体颜色方法

    <script type="text/javascript">var all=document.getElementById("big");var ...

  4. 《BI那点儿事—数据的艺术》目录索引

    原创·<BI那点儿事—数据的艺术>教程免费发布 各位园友,大家好,我是Bobby,在学习BI和开发的项目的过程中有一些感悟和想法,整理和编写了一些学习资料,本来只是内部学习使用,但为了方便 ...

  5. Nodejs学习总结 -Express 登录注册示例(二)

    项目创建后,我们来做个登录注册实例,详细操作步骤如下. 1.新建项目demo ,具体操作步骤参考上一章内容 https://www.cnblogs.com/Anlycp/ 2.添加mysql和sess ...

  6. 老王讲自制RPC框架.(四.序列化与反序列化)

    #(序列化) 在实际的框架中,真正影响效率的就是数据的传输方式,以及传输的准备,或者说是tcp与http,序列化.当然要想提高整个框架的效率,需要采用一种高效的序列化 框架比如流行的protostuf ...

  7. python学习--字符串

    python的字符串类型为str 定义字符串可以用 ‘abc' , "abc", '''abc''' 查看str的帮助 在python提示符里 help(str) python基于 ...

  8. Failed: error processing document #281: unexpected EOF,往MongoDB当中插入json文件时出现的错误。

    往MongoDB当中插入json文件时提示的错误(我的操作系统是win10): 当时的执行命令是:mongoimport -d test -c restaurants d://primer-datas ...

  9. [WPF]ComboBox.Items为空时,点击不显示下拉列表

    ComboBox.Items为空时,点击后会显示空下拉列表: ComboBox点击显示下拉列表,大概原理为: ComboBox存在ToggleButton控件,默认ToggleButton.IsChe ...

  10. 使用Kylin构建企业大数据分析平台的4种部署方式

    本篇博客重点介绍如何使用Kylin来构建大数据分析平台.根据官网介绍,其实部署Kylin非常简单,称为非侵入式安装,也就是不需要去修改已有的 Hadoop大数据平台.你只需要根据的环境下载适合的Kyl ...