iOS Core Animation Advanced Techniques-变换
上四章节:
这篇随笔主要介绍有关图层变换。
- 变换:
- 对图层旋转,摆放或者扭曲的CGAffineTransform,可以将扁平物体转换成三维空间对象的CATransform3D
- 仿射(图层中平行的两条线在变换之后任然保持平行)变换:
- CGAffineTransform属性(仅对2D变换有效)
- 用于在二维空间做旋转,缩放与平移
- CGAffineTransform属性(仅对2D变换有效)
CALayer的affineTransform属性就是一个CGAffineTransform类型对象,UIView对应的属性为transform属性
CALayer的transform属性是一个CATransform3D类型而不是CGAffineTransform类型
系统提供创建CGAffineTransform实例对象的主要3个方法:
- CGAffineTransformMakeRotation(CGFloat angle);//旋转
- CGAffineTransformMakeScale(CGFloat sx,CGFloat sy);//缩放
- CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty);//平移
-
-
- 使用例子:
- CGAffineTransform transform=CGAffineTransformMakeRotation(M_PI_4);//iOS的变换函数使用弧度而不是角度作为单位
- myView.layer.affineTransform=transform;
-
- 混合变换:
在一个变换的基础上做更深层次的变换,如做一个既要缩放又要旋转的变换,使用以下3个函数:
- CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
- CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
- CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
-
- 实现过程中一般先生成一个CGAffineTransform类型的空值,通过CGAffineTransformIdentity()函数获取
- 如果需要混合两个已经存在的变换矩阵,就可以使用如下方法,在两个变换的基础上创建一个新的变换:
- CGAffineTransform totalAffineTransform=CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
- 使用例子:
- //实现先缩小50%,再旋转30度,最后向右移动200个像素
- CGAffineTransform transform=CGAffineTransformIdentity;
- transform=CGAffineTransformScale(transform,0.5,0.5);
- transform=CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
- transform = CGAffineTransformTranslate(transform, 200, 0);
- myView.layer.affineTransform=transform;
注意:
当你按顺序做了变换,上一个变换的结果将会影响之后的变换,所以200像素的向右平移同样也被旋转了30度,缩小了50%,所以它实际上是斜向移动了100像素
意味着变换的顺序会影响最终的结果,也就是说旋转之后的平移和平移之后的旋转结果可能不同
- 剪切变换:
如一个矩形变成了一个平行四边形(倾斜)
-
- 使用例子:
- CGAffineTransform transform=CGAffineTransformIdentity;
- transform.c=-1.0f;
- transform.b=0f;
- myView.layer.affineTransform=transform;
- 3D变换:
- transform属性
- 是一个CATransform3D类型,UIView上没有对应属性
- CG前缀属于Core Graphics框架(2D绘图API),CGAffineTransform仅对2D变换有效
- 系统提供创建CATransform3D实例对象的主要3个方法:(对比Core Graphics的2D函数多出z轴参数)
- transform属性
- CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
- CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) ;
- CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz);
-
-
-
- 使用例子:
- CATransform3D transform=CATransform3DMakeRotation(M_PI_4,0,1,0);
- myView.layer.transform=transform;
- 注意:若不设置透视投影效果,视图看起来没有斜向视角效果
-
-
- 透视投影:
- CATransform3D的m34属性用来做透视
- m34默认值为0
- 通过设置m34为-1.0/d应用透视效果,d代表视角与事物距离,通常设置为500-1000
- 使用例子:
- CATransform3D transform=CATransform3DIdentity;
- transform.m34=-1.0/500.0;
- transform=CATransform3DRotate(transform,M_PI_4,0,1,0);
- myView.layer.transform=transform;
- CATransform3D的m34属性用来做透视
- sublayerTransform属性:
- 是一个CATransform3D类型,设置该属性会影响到所有的子图层,一次性对包含这些图层的容器做变换,所有子图层自动继承该变换方法
- 使用例子:
- [myContainerView addSubView:myView1];
- [myContainerView addSubView:myView2];
- CATransform3D perspective=CATransform3DIdentity;
- perspective.m34=-1.0/500.0;
- myContainerView.layer.sublayerTransform=perspective;
- CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
- myView1.layer.transform=transform1;
- CATransform3D transform2=CATransform3DMakeRotation(-M_PI_4,0,1,0);
- myView2.layer.transform=transform2;
- 是一个CATransform3D类型,设置该属性会影响到所有的子图层,一次性对包含这些图层的容器做变换,所有子图层自动继承该变换方法
- 背面:
- 默认图层是双面绘制,反面显示的是正面的一个镜像图片(不需要的时候会造成资源浪费)
- 通过设置CALayer上的doubleSided属性为NO不绘制背面寄宿图内容
- 扁平化图层:
- 内部图层相对外部图层做了相反的变换,那么这两个变换将被相互抵消(绕Z轴做的变换);
- 如:
- CATransform3D outer = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
- outerView.layer.transform = outer;
- CATransform3D inner = CATransform3DMakeRotation(-M_PI_4, 0, 0, 1);
- innerView.layer.transform = inner;
- 若不是绕Z轴做的变换,而是Y轴,那么由于每个图层的3D场景是扁平化的,也就是有图层模拟出来的立体场景,倾斜时,子图层仍是被扁平贴在父视图上,父子层面永远平行,此时两相反变化没有呈现抵消效果
- 如:
- CATransform3D outer = CATransform3DIdentity;
- outer.m34 = -1.0 / 500.0;
- outer = CATransform3DRotate(outer, M_PI_4, 0, 1, 0);
- self.outerView.layer.transform = outer;
- CATransform3D inner = CATransform3DIdentity;
- inner.m34 = -1.0 / 500.0;
- inner = CATransform3DRotate(inner, -M_PI_4, 0, 1, 0);
- self.innerView.layer.transform = inner;
- 内部图层相对外部图层做了相反的变换,那么这两个变换将被相互抵消(绕Z轴做的变换);
- 固体对象:
- 固态的3D对象,实际上是一个技术上所谓的空洞对象,但整体以固态呈现
- 用几面图层经位移旋转拼凑而成的固体,如使用例子:
- @interface ViewController ()
- @property (nonatomic, weak) IBOutlet UIView *containerView;
- @property (nonatomic, strong) IBOutletCollection(UIView) NSArray *faces;
- @end
- @implementation ViewController
- - (void)addFace:(NSInteger)index withTransform:(CATransform3D)transform{
- //get the face view and add it to the container
- UIView *face = self.faces[index];
- [self.containerView addSubview:face];
- //center the face view within the container
- CGSize containerSize = self.containerView.bounds.size;
- face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
- // apply the transform
- face.layer.transform = transform;
- }
- - (void)viewDidLoad{
- [super viewDidLoad];
- //set up the container sublayer transform
- CATransform3D perspective = CATransform3DIdentity;
- perspective.m34 = -1.0 / 500.0;
- perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
- perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
- self.containerView.layer.sublayerTransform = perspective;
- //add cube face 1
- CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
- [self addFace:0 withTransform:transform];
- //add cube face 2
- transform = CATransform3DMakeTranslation(100, 0, 0);
- transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
- [self addFace:1 withTransform:transform];
- //add cube face 3
- transform = CATransform3DMakeTranslation(0, -100, 0);
- transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
- [self addFace:2 withTransform:transform];
- //add cube face 4
- transform = CATransform3DMakeTranslation(0, 100, 0);
- transform = CATransform3DRotate(transform, -M_PI_2, 1, 0, 0);
- [self addFace:3 withTransform:transform];
- //add cube face 5
- transform = CATransform3DMakeTranslation(-100, 0, 0);
- transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
- [self addFace:4 withTransform:transform];
- //add cube face 6
- transform = CATransform3DMakeTranslation(0, 0, -100);
- transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
- [self addFace:5 withTransform:transform];
- }
- @end
- 光亮与阴影:
- 可以通过改变每个面的背景颜色或者直接用带光亮效果的图片来调整
- 用GLKit框架来做向量的计算(略)
- 点击事件:
- 点击事件的处理由视图在父视图中的顺序决定的,并不是3D空间中的Z轴顺序
- 当立体显示视图时因响应顺序问题导致事件拦截的问题,解决方案:
- 把除了表面的其他视图userInteractionEnabled属性都设置成NO来禁止事件传递。
- 或者简单通过代码把视图覆盖在拦截了事件的视图上。