CATransformLayer

关于CATransformLayer的介绍请参考专用图层。

什么时候使用CATransformLayer?

Core Animation中的3D绘画介绍(第一部分)中有介绍WORK WITH CATRANSFORMLAYER,大致的翻译下:

坦白的讲,CALayer并不是3D层级的root的合适选择。函数E_multiplePlanesZAxis将会告诉我们为什么会是这样。
在这个场景中,我们在相同的X,Y坐标系中创建4个平面(plane),但是却对应有不同的Z坐标。
purplePlane是最靠近你的view,而YellowPlane是最远的。

//给planes应用变换
t = CATransform3DIdentity;
t = CATransform3DTranslate(t, 0, 0, -10);
purplePlane.transform = t;

t = CATransform3DIdentity;
t = CATransform3DTranslate(t, 0, 0, -50);
redPlane.transform = t;

t = CATransform3DIdentity;
t = CATransform3DTranslate(t, 0, 0, -90);
orangePlane.transform = t;

t = CATransform3DIdentity;
t = CATransform3DTranslate(t, 0, 0, -130);
yellowPlane.transform = t;

在创建这些planes之前,给container 应用一个rotation变换(这里的container是一个CALayer)。

//给container应用变化
CATransform3D t = CATransform3DIdentity;
t.m34 = 1.0/-500;
t = CATransform3DRotate(t, 80.0f * M_PI / 180.0f, 0, 1, 0);
container.transform = t;

你期望的结果可能是这样的:
CATransformLayer_第1张图片

但最终的结果却是这样的:
CATransformLayer_第2张图片

这是因为CALayer不能够管理3D层级的深度,它只是flattens the scene to a single Z level.

为了修正这个问题,获得正确的结果,要选择CATransformLayers作为root object。

在函数F_multiplePlanesZAxis中修改这个问题:

//Create the container as a CATransformLayer
CATransformLayer *container = [CATransformLayer layer];
container.frame = CGRectMake(0, 0, 640, 300);
[self.view.layer addSublayer:container];

CATransformLayer是一个特殊的layer。与CALayers不同的是,只有它的子layer才会被渲染,其它的属性,比如backgroundColor、contents、border等等,都会被忽略。

[Core Animation中的3D绘画介绍(第二部分)](http://www.thinkandbuild.it/introduction-to-3d-drawing-in-core-animation-part-2/)

在这个教程中,创建一个类似旋转木马类似的场景,可以通过拖动手势来交互。效果如下:

CATransformLayer_第3张图片


We go 3D!
为了创建carousel,我们需要创建3D层级,使用CATransformLayer作为层级的root是个好方法。

The planes平面
Carousel由一系列平面组成。我们使用CAGradientLayer来描述这些对象,它是CALayer的子类,让我们可以使用渐变的颜色来定义背景颜色。
plane需要移动和旋转来围成一个圆形。

手势
使用了一个手势,来追踪用户的的动作,把手势的数据转为角度值,来执行carousel的旋转。

LET’S CODE!


打开ViewController.m,从viewDidLoad:函数开始:

- (void)viewDidLoad
{
    [super viewDidLoad];

    //初始化TransformLayer
    transformLayer = [CATransformLayer layer];
    transformLayer.frame = self.view.bounds;
    [self.view.layer addSublayer:transformLayer];

    angle = 0;
    XPanOffset = 0;

    //创建5个planes
    [self addPlane];
    [self addPlane];
    [self addPlane];
    [self addPlane];
    [self addPlane];

    //强制开始第一个动画,来设置plane的位置
    [self animate];

    //初始化拖动手势
    UIPanGestureRecognizer *panGesture =  [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    [self.view addGestureRecognizer:panGesture];   
}

绘制Planes

addPlane函数是很简单明了的。它创建CAGradientLayer,并把它作为transformLayer的sublayer。

/**创建一个CAGradientLayer**/
-(void)addPlane{

    CGSize planeSize = CGSizeMake(250, 150);

    //初始化图层
    CAGradientLayer *layer = [CAGradientLayer layer];

    //设置frame和锚点
    layer.frame = CGRectMake(480/2 - planeSize.width/2, 320/2 - planeSize.height/2 -20, planeSize.width, planeSize.height);
    layer.anchorPoint = CGPointMake(0.5, 0.5);

    //设计边框和圆角
    layer.borderColor = [[UIColor colorWithWhite:1.0 alpha:0.3]CGColor];
    layer.cornerRadius = 10;
    layer.borderWidth = 4;

    //设置渐变的颜色
    layer.colors = [NSArray arrayWithObjects:
                    (id)[UIColor purpleColor].CGColor,
                    (id)[UIColor redColor].CGColor,
                    nil];
    layer.locations = [NSArray arrayWithObjects:
                       [NSNumber numberWithFloat:0.0f],
                       [NSNumber numberWithFloat:1.0f],
                       nil];

    //设置阴影
    layer.shadowColor = [[UIColor blackColor]CGColor];
    layer.shadowOpacity = 1;
    layer.shadowRadius = 20;

    //doubleSided设为yes,如果想在face被转过去的时候能被看见
    layer.doubleSided = YES;

    //添加到transformLayer上
    [transformLayer addSublayer:layer];
}

CATransformLayer_第4张图片

定位Planes POSITIONING THE PLANES


在plane被创建后,在viewDidLoad方法中,我们调用了animate
这个方法的主要功能是更新Plane的位置。在我们第一次调用animate时,触摸事件并没有发生。

/** This function performs the transformation on each plane **/
-(void)animate{

    //每个plane对应的角度
    float degForPlane = 360 / [[transformLayer sublayers] count];

    //当前角度的偏移量
    float degX = angle;


    for (CALayer *layer in [transformLayer sublayers]) {
        //Create the Matrix identity
        CATransform3D t = CATransform3DIdentity;
        //Setup the perspective modifying the matrix elementat [3][4]
        t.m34 = 1.0f / - 1000.0f;

        //旋转
        t = CATransform3DRotate(t, degToRad(degX), 0.0f, 1.0f, 0.0f);

        //移动
        t = CATransform3DTranslate(t, 0.0f, 0.0f,  250.0f);

        //禁止动画
        [CATransaction setAnimationDuration:0.0];

        //在当前的layer上执行动画
        layer.transform = t;

        //Add the degree needed for the next plane
        degX += degForPlane;
    }
}

defForPlane变量是每一个plane要在先前的plane上旋转的角度值,来形成一个360的圈。用图片解释如下:
CATransformLayer_第5张图片

如果仅仅是添加了旋转,结果是这样的:
CATransformLayer_第6张图片

拖动手势

-(void)pan:(UIPanGestureRecognizer*)gesture{

    //获取x方向上的位移
    float xOffset = [gesture translationInView:self.view].x;

    //在手势开始的时候,offset重置为0
    if(gesture.state == UIGestureRecognizerStateBegan){
        XPanOffset = 0;
    }

    //the distance covered since the last gesture event (I slow down a bit the final rotation multiplying by 0.5)
    float movedBy = xOffset * 0.5 - XPanOffset;

    //Calculate the offset from the previous gesture event
    XPanOffset += movedBy;

    //Add the offset to the current angle
    angle += movedBy;

    //Update the plane
    [self animate];

}

你可能感兴趣的:(iOS,CALayer)