第五章: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. How To Install Java on CentOS and Fedora

    PostedDecember 4, 2014 453.8kviews JAVA CENTOS FEDORA   Introduction This tutorial will show you how ...

  2. 。U盘安装CentOS6.5

    最近着手自学Linux,网上有很多CentOS的各种版本,但查阅到的教程基本都是关于CentOS6的,本着最新的版本并不一定是最适合的版本的原则,我选择安装CentOS6.5.安装系统稍微不注意就会出 ...

  3. xib的UIScrollView自适应高度

    1.首先,我们先把这个size classes关了(需要使用的童鞋无视掉,也无视掉我的工程名,这是我弄高德地图创建的工程) 2.添加一个scrollview上去,设置上下左右约束为0 3.然后搞一个v ...

  4. Mifare系列6-射频卡与读写器的通信(转)

    文/闫鑫原创转载请注明出处http://blog.csdn.net/yxstars/article/details/38085415 1. 复位应答(Answer to request) 读写器呼叫磁 ...

  5. validate插件深入学习-01 小白从看透一个插件开始

    没有编程基础的的我,即使看了一遍jq文档也不知道怎么写程序,一个新的插件看了也不知道怎么用. 总是想做自己会的,自己不会的永远不去触碰,就永远不会. 都说编程这东西,很多都有很像的地方了,一个语言学通 ...

  6. js 中与元素有关的高度

    1, 平常都经常用 document.documentElement.clientWidth 或 document.documentElement.clientHeight 来获取页面的宽度和高度, ...

  7. Asp.Net_Mvc_@Html.xxx()的扩展

    /// <summary> /// 生成分类下拉-列表框,选中指定的项 /// </summary> /// <param name="html"&g ...

  8. UIStackView使用 (堆视图)

    一基本使用 1创建多个子控件 for (int i = 0; i < 3; i++) { UIButton *imgBtn = [UIButton buttonWithType:UIButton ...

  9. Python中Paramiko协程方式详解

    什么是协程 协程我们可以看做是一种用户空间的线程. 操作系统对齐存在一无所知,需要用户自己去调度. 比如说进程,线程操作系统都是知道它们存在的.协程的话是用户空间的线程,操作系统是不知道的. 为什么要 ...

  10. eclipse中的web环境配置

    一.tomcat的安装 直接官网下载,选择自动配置安装Exe文件. 测试: 1.启动安装目录下bin文件中的exe文件,观察是否安装完好.若出现打断文字黑框,则说明已经安装完好. 2.输入网址.htt ...