详解CATransformLayer
CATransformLayer与CALayer有着细微的差别,但这些差别会影响到3D变换的动画效果.
动画都有坐标系,如下所示(注意,这个不是iOS中的坐标系,请勿对号入座):
iOS中layer的锚点就在坐标系的正中间.
layer的position可以理解为View的center.
实现带有3d景深效果动画:
//
// RootViewController.m
// CATransformLayer
//
// Copyright (c) 2014年 Y.X. All rights reserved.
//
#import "RootViewController.h"
#import "YXGCD.h"
@interface RootViewController ()
@property (nonatomic, strong) GCDTimer *timer;
@end
@implementation RootViewController
#define V_CENTER_X self.view.center.x
#define V_CENTER_Y self.view.center.y
#define CG_COLOR(R, G, B, A) [UIColor colorWithRed:(R) green:(G) blue:(B) alpha:(A)].CGColor
#define DEGREE(d) ((d) * M_PI / 180.0f)
- (void)viewDidLoad
{
[super viewDidLoad];
// 普通的一个layer
CALayer *plane = [CALayer layer];
plane.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane.position = CGPointMake(V_CENTER_X, V_CENTER_Y); // 位置
plane.opacity = 0.6; // 背景透明度
plane.backgroundColor = CG_COLOR(1, 0, 0, 1); // 背景色
plane.borderWidth = 3; // 边框宽度
plane.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane.cornerRadius = 10; // 圆角值
// 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
[container addSublayer:plane];
// 启动定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
static float degree = 0.f;
// 起始值
CATransform3D fromValue = CATransform3DIdentity;
fromValue.m34 = 1.0/ -500;
fromValue = CATransform3DRotate(fromValue, degree, 0, 1, 0);
// 结束值
CATransform3D toValue = CATransform3DIdentity;
toValue.m34 = 1.0/ -500;
toValue = CATransform3DRotate(toValue, degree += 45.f, 0, 1, 0);
// 添加3d动画
CABasicAnimation *transform3D = [CABasicAnimation animationWithKeyPath:@"transform"];
transform3D.duration = 1.f;
transform3D.fromValue = [NSValue valueWithCATransform3D:fromValue];
transform3D.toValue = [NSValue valueWithCATransform3D:toValue];
plane.transform = toValue;
[plane addAnimation:transform3D forKey:@"transform3D"];
} timeInterval:NSEC_PER_SEC];
[_timer start];
}
@end
下图中的m34值代表着景深效果,非常关键,其值越接近0,景深效果就越发强烈
如果写成这样子:
那么显示就会变成:
毫无3d感可言.
将景深效果添加到容器上面去我们就能得到如下的效果:
- (void)viewDidLoad
{
[super viewDidLoad];
// 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane1.position = CGPointMake(60, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(1, 0, 0, 1); // 背景色
plane1.borderWidth = 3; // 边框宽度
plane1.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = 10; // 圆角值
// 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane2.position = CGPointMake(60 + 110, V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(0, 1, 0, 1); // 背景色
plane2.borderWidth = 3; // 边框宽度
plane2.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = 10; // 圆角值
// 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
CATransform3D plane_3D = CATransform3DIdentity;
plane_3D.m34 = 1.0/ -500;
plane_3D = CATransform3DRotate(plane_3D, DEGREE(30), 0, 1, 0);
container.transform = plane_3D;
[container addSublayer:plane1];
[container addSublayer:plane2];
}
注意,下图红框中的值是非常关键的哦:
到这里还没讲CATransformLayer呢,先看个例子:
效果如下:
- (void)viewDidLoad
{
[super viewDidLoad];
// 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane1.position = CGPointMake(200, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(1, 0, 0, 1); // 背景色
plane1.borderWidth = 3; // 边框宽度
plane1.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = 10; // 圆角值
// Z轴平移
CATransform3D plane1_3D = CATransform3DIdentity;
plane1_3D = CATransform3DTranslate(plane1_3D, 0, 0, -10);
plane1.transform = plane1_3D;
// 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane2.position = CGPointMake(200, V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(0, 1, 0, 1); // 背景色
plane2.borderWidth = 3; // 边框宽度
plane2.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = 10; // 圆角值
// Z轴平移
CATransform3D plane2_3D = CATransform3DIdentity;
plane2_3D = CATransform3DTranslate(plane2_3D, 0, 0, -30);
plane2.transform = plane2_3D;
// 创建容器layer
CALayer *container = [CALayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
// 以Y轴为坐标系,旋转45度
CATransform3D t = CATransform3DIdentity;
t.m34 = 1.0/-500;
t = CATransform3DRotate(t, DEGREE(45), 0, 1, 0);
container.transform = t;
[container addSublayer:plane1];
[container addSublayer:plane2];
}
如果把上图的CALayer替换成下图的CATransformLayer
则会产生如下的效果:
看到上面的图,你应该就明白了CATransformLayer当做容器是为了给里面的Layer提供景深效果用的.
再来做成动画看看效果吧:
- (void)viewDidLoad
{
[super viewDidLoad];
// 普通的一个layer
CALayer *plane1 = [CALayer layer];
plane1.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane1.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane1.position = CGPointMake(200, V_CENTER_Y); // 位置
plane1.opacity = 0.6; // 背景透明度
plane1.backgroundColor = CG_COLOR(1, 0, 0, 1); // 背景色
plane1.borderWidth = 3; // 边框宽度
plane1.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane1.cornerRadius = 10; // 圆角值
// Z轴平移
CATransform3D plane1_3D = CATransform3DIdentity;
plane1_3D = CATransform3DTranslate(plane1_3D, 0, 0, -10);
plane1.transform = plane1_3D;
// 普通的一个layer
CALayer *plane2 = [CALayer layer];
plane2.anchorPoint = CGPointMake(0.5, 0.5); // 锚点
plane2.frame = (CGRect){CGPointZero, CGSizeMake(100, 100)}; // 尺寸
plane2.position = CGPointMake(200, V_CENTER_Y); // 位置
plane2.opacity = 0.6; // 背景透明度
plane2.backgroundColor = CG_COLOR(0, 1, 0, 1); // 背景色
plane2.borderWidth = 3; // 边框宽度
plane2.borderColor = CG_COLOR(1, 1, 1, 0.5); // 边框颜色(设置了透明度)
plane2.cornerRadius = 10; // 圆角值
// Z轴平移
CATransform3D plane2_3D = CATransform3DIdentity;
plane2_3D = CATransform3DTranslate(plane2_3D, 0, 0, -30);
plane2.transform = plane2_3D;
// 创建容器layer
CATransformLayer *container = [CATransformLayer layer];
container.frame = self.view.bounds;
[self.view.layer addSublayer:container];
[container addSublayer:plane1];
[container addSublayer:plane2];
// 启动定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
static float degree = 0.f;
// 起始值
CATransform3D fromValue = CATransform3DIdentity;
fromValue.m34 = 1.0/ -500;
fromValue = CATransform3DRotate(fromValue, degree, 0, 1, 0);
// 结束值
CATransform3D toValue = CATransform3DIdentity;
toValue.m34 = 1.0/ -500;
toValue = CATransform3DRotate(toValue, degree += 45.f, 0, 1, 0);
// 添加3d动画
CABasicAnimation *transform3D = [CABasicAnimation animationWithKeyPath:@"transform"];
transform3D.duration = 1.f;
transform3D.fromValue = [NSValue valueWithCATransform3D:fromValue];
transform3D.toValue = [NSValue valueWithCATransform3D:toValue];
container.transform = toValue;
[container addAnimation:transform3D forKey:@"transform3D"];
} timeInterval:NSEC_PER_SEC];
[_timer start];
}