IOS 3D UI --- CALayer的transform扩展

例子代码可以在 http://download.csdn.net/detail/worldmatrix/4603488 下载
 
  iOS的UI是基于UIView类的,我们能看到的每个UI元素都是UIView或者UIView的子类。View按树形结构组织起来,树根是UIWindow。
     View负责界面的交互和显示,其中显示部分由CALayer来完成。每个UIView包含一个CALayer实例。可以这么认为,UIView本身是不可见的,我们能看到的都是CALayer,UIView只是负责对CALayer进行管理。
 
 
UIView的显示设置都是对CALayer属性的封装,但是这层封装掩盖了CALayer提供的3D显示功能。所以我们想让UIView显示3D的效果的话,需要直接操作CALayer。
 
  要操作CALayer对象,首先要在工程中包含QuartzCore.framework,在文件中import
<QuartzCore/QuartzCore.h>头文件。QuartzCore.framework中包含了CALayer以及CALayer一些官方子类的定义。
 
 
通过设置CALayer的transform属性,可以使CALayer产生3D空间内的平移、缩放、旋转等变化。
 
  第一个例子,绕坐标轴的旋转:
    原始场景如图 

 
 
 
使用 image.layer.transform = CATransform3DMakeRotation(M_PI/6, 0, 0, 1);
绕Z轴旋转30度后的效果

 
    使用 image.layer.transform = CATransform3DMakeRotation(M_PI/6,
0, 1, 0); 绕Y轴旋转30度后的效果

 
    使用 image.layer.transform = CATransform3DMakeRotation(M_PI/6,
1, 0, 0); 绕X轴旋转30度后的效果

 
 
 
能够发现,绕Z轴的旋转比较符合预期,但是绕X轴Y轴的旋转只是在Y轴X轴上进行了一些缩放而已。这是因为,在CALayer的显示系统中,默认的相机使用正交投影,正交投影没有远小近大效果,所以在本例中,只能造成相应轴上的缩放。
 
  第二个例子,透视投影
   
CALayer默认使用正交投影,因此没有远小近大效果,而且没有明确的API可以使用透视投影矩阵。所幸可以通过矩阵连乘自己构造透视投影矩阵。构造透视投影矩阵的代码如下:
    CATransform3D
CATransform3DMakePerspective(CGPoint center, float
disZ)
    {
   
    CATransform3D transToCenter =
CATransform3DMakeTranslation(-center.x, -center.y, 0);
 
      CATransform3D transBack =
CATransform3DMakeTranslation(center.x, center.y, 0);
 
      CATransform3D scale =
CATransform3DIdentity;
   
    scale.m34 = -1.0f/disZ;
   
    return
CATransform3DConcat(CATransform3DConcat(transToCenter, scale),
transBack);
    }

    CATransform3D
CATransform3DPerspect(CATransform3D t, CGPoint center, float
disZ)
    { 
 
      return CATransform3DConcat(t,
CATransform3DMakePerspective(center,
disZ));
    }

 
 
这个函数的实现原理要参考计算机图形学的3D变换部分,以后再做解释。现在只需要了解接口的含义,center指的是相机 的位置,相机的位置是相对于要进行变换的CALayer的来说的,原点是CALayer的anchorPoint在整个CALayer的位置,例如CALayer的大小是(100,
200), anchorPoint值为(0.5, 0.5),此时anchorPoint在整个CALayer中的位置就是(50,
100),正中心的位置。传入透视变换的相机位置为(0, 0),那么相机所在的位置相对于CALayer就是(50,
100)。如果希望相机在左上角,则需要传入(-50,
-100)。disZ表示的是相机离z=0平面(也可以理解为屏幕)的距离。
   
带透视效果的旋转,效果如下:

 
    CATransform3D rotate
= CATransform3DMakeRotation(M_PI/6, 1, 0, 0);
    image.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 200);

 
  

 

    CATransform3D rotate
= CATransform3DMakeRotation(M_PI/6, 0,
1, 0);
    image.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 200);

 
  

 

    CATransform3D rotate
= CATransform3DMakeRotation(M_PI/6, 0, 0,
1);
    image.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 200);
 
 
image的默认anchorPoint为(0.5,0.5),也就是在图片中心;眼睛在图片中心点,距屏幕200单位。可以观察到,因为翻转,使图片的不同部分离屏幕距离不同,近大远小的效果使立体感大大提升。饶Z轴的旋转不因为透视产生变化,因为所有的点离屏幕距离相同,所以不会产生近大远小的透视感。

 
 
第三,更多的效果。CALayer的旋转和缩放是绕anchorPoint点的,改变anchorPoint的值,可以使Layer绕不同的点而不只是中心点旋转缩放。在构造透视投影矩阵的例子中就可以看到,CATransform3D可以使用CATransform3DConcat函数连接起来以构造更复杂的变换。通过这些方法,可以组合出更多的效果来。下面是个翻转的动画。使用UITimer

 
 
  -
(void)update
    {
 
      static float angle
= 0;
        angle
+= 0.05f;

CATransform3D transloate
= CATransform3DMakeTranslation(0, 0, -200);
 
      CATransform3D rotate
= CATransform3DMakeRotation(angle, 0, 1, 0);
 
      CATransform3D mat
= CATransform3DConcat(rotate, transloate);
   
    image.layer.transform = CATransform3DPerspect(mat, CGPointMake(0, 0), 500);
    }

 
  最后是两个更复杂的例子。第一个是使用四张同样大小的图片围成一个框,让这个框动画旋转。

 
 
  CATransform3D move
= CATransform3DMakeTranslation(0, 0, 160);
CATransform3D back
= CATransform3DMakeTranslation(0, 0, -160);

 
  CATransform3D rotate0
= CATransform3DMakeRotation(-angle, 0, 1, 0);
 
  CATransform3D rotate1
= CATransform3DMakeRotation(M_PI_2-angle, 0, 1, 0);
 
  CATransform3D rotate2
= CATransform3DMakeRotation(M_PI_2*2-angle, 0, 1, 0);
 
  CATransform3D rotate3
= CATransform3DMakeRotation(M_PI_2*3-angle, 0, 1, 0);

CATransform3D mat0
= CATransform3DConcat(CATransform3DConcat(move, rotate0),
back);
CATransform3D mat1
= CATransform3DConcat(CATransform3DConcat(move, rotate1),
back);
CATransform3D mat2
= CATransform3DConcat(CATransform3DConcat(move, rotate2),
back);
CATransform3D mat3
= CATransform3DConcat(CATransform3DConcat(move, rotate3),
back);

image0.layer.transform = CATransform3DPerspect(mat0, CGPointZero, 500);
image1.layer.transform = CATransform3DPerspect(mat1, CGPointZero, 500);
image2.layer.transform = CATransform3DPerspect(mat2, CGPointZero, 500);
image3.layer.transform = CATransform3DPerspect(mat3, CGPointZero, 500);

 
 上面的例子都使用UIImage的CALayer,但CALayer产生的动画可以应用在所有的UIView及子类上,下面是个普通界面的立体翻转效果。

 
    float dis
= 160 * 1.732f;
CATransform3D move
= CATransform3DMakeTranslation(0, 0,
dis);
CATransform3D back
= CATransform3DMakeTranslation(0, 0, -dis);

 
  CATransform3D rotate0
= CATransform3DMakeRotation(-angle, 0, 1, 0);
 
  CATransform3D rotate1 = CATransform3DMakeRotation(-angle
+ M_PI/3.0f, 0, 1, 0);

CATransform3D mat0
= CATransform3DConcat(CATransform3DConcat(move, rotate0),
back);
CATransform3D mat1
= CATransform3DConcat(CATransform3DConcat(move, rotate1),
back);

view0.layer.transform = CATransform3DPerspect(mat0, CGPointZero, 500);

时间: 2024-08-09 02:20:23

IOS 3D UI --- CALayer的transform扩展的相关文章

【转】如何在IOS中使用3D UI - CALayer的透视投影

原文网址:http://www.tairan.com/archives/2041/ 例子代码可以在 http://www.tairan.com/thread-3607-1-1.html 下载 iOS的UI是基于UIView类的,我们能看到的每个UI元素都是UIView或者UIView的子类.View按树形结构组织起来,树根是UIWindow. View负责界面的交互和显示,其中显示部分由CALayer来完成.每个UIView包含一个CALayer实例.可以这么认为,UIView本身是不可见的,我

iOS开发——UI篇OC&amp;transform详解

transframe属性详解 1. transform属性 在OC中,通过transform属性可以修改对象的平移.缩放比例和旋转角度 常用的创建transform结构体方法分两大类 (1) 创建“基于控件初始位置”的形变 CGAffineTransformMakeTranslation(平移) CGAffineTransformMakeScale(缩放) CGAffineTransformMakeRotation(旋转) (2) 创建“基于transform参数”的形变 CGAffineTra

iOS开发UI篇—CAlayer简介

iOS开发UI篇—CALayer简介 一.简单介绍 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层,在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层 @property(nonatomic,readonly,retain) CALayer *layer; 当

iOS开发UI篇—CAlayer(自定义layer)

iOS开发UI篇—CAlayer(自定义layer) 一.第一种方式 1.简单说明 以前想要在view中画东西,需要自定义view,创建一个类与之关联,让这个类继承自UIView,然后重写它的DrawRect:方法,然后在该方法中画图. 绘制图形的步骤: (1)获取上下文 (2)绘制图形 (3)渲染图形 如果在layer上画东西,与上面的过程类似. 代码示例: 新建一个类,让该类继承自CALayer YYMylayer.m文件 1 // 2 // YYMylayer.m 3 // 05-自定义l

iOS开发UI篇—CAlayer(创建图层)

iOS开发UI篇—CAlayer(创建图层) 一.添加一个图层 添加图层的步骤: 1.创建layer 2.设置layer的属性(设置了颜色,bounds才能显示出来) 3.将layer添加到界面上(控制器view的layer上) 1 // 2 // YYViewController.m 3 // 01-创建一个简单的图层 4 // 5 // Created by apple on 14-6-21. 6 // Copyright (c) 2014年 itcase. All rights reser

iOS开发UI篇—CAlayer层的属性(转摘)

iOS开发UI篇—CAlayer层的属性 一.position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性:position和anchorPoint @property CGPoint position; 用来设置CALayer在父层中的位置 以父层的左上角为原点(0, 0) @property CGPoint anchorPoint; 称为“定位点”.“锚点” 决定着CALayer身上的哪个点会在position属性所指的位置 以自己的左上角为原点(0, 0) 它

iOS开发UI篇—CAlayer(创建图层)(转摘)

iOS开发UI篇—CAlayer(自定义layer) 一.第一种方式 1.简单说明 以前想要在view中画东西,需要自定义view,创建一个类与之关联,让这个类继承自UIView,然后重写它的DrawRect:方法,然后在该方法中画图. 绘制图形的步骤: (1)获取上下文 (2)绘制图形 (3)渲染图形 如果在layer上画东西,与上面的过程类似. 代码示例: 新建一个类,让该类继承自CALayer YYMylayer.m文件 1 // 2 // YYMylayer.m 3 // 05-自定义l

iOS开发UI篇—核心动画(基础动画)

iOS开发UI篇—核心动画(基础动画) 一.简单介绍 CAPropertyAnimation的子类 属性解析: fromValue:keyPath相应属性的初始值 toValue:keyPath相应属性的结束值 随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue 如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态.但

iOS开发UI篇—核心动画(关键帧动画)

iOS开发UI篇—核心动画(关键帧动画) 一.简单介绍 是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值 属性解析: values:就是上述的NSArray对象.里面的元素称为”关键帧”(keyframe).动画对象会在指定的时间(duration)内,依次显示values数组