Core Animation 四 (三维动画)

前面的三篇文章介绍了如何使用CGAffineTransform来使UIView绘图更有效率。这个技术限制你只能进行二维变形:平移、旋转、缩放和倾斜。而在图层中,可以通过添加视角来应用三维变形。这常常被称为2.5D,因为他不能让图层真正成为三维对象(和OPENGL ES不同)。不过,它确实模拟出了三维的运动效果。

旋转图层基于一个锚点进行。默认情况下,抹点位于图层中心,一般式{0.5,0.5}。你可以将它移到图层中的任何位置,以便于围绕一条边或一个角旋转。锚点的度量以单位方形而不是点为参照。所以无论图层有多大,右下角的坐标都是{1.0,1.0};

下面是一个三维盒子的例子

BoxViewController.h

@interface BoxViewController : UIViewController { 
    
}
@property (nonatomic,readwrite,strong) CALayer *topLayer;
@property (nonatomic,readwrite,strong) CALayer *bottomLayer;
@property (nonatomic,readwrite,strong) CALayer *leftLayer;
@property (nonatomic,readwrite,strong) CALayer *rightLayer;
@property (nonatomic,readwrite,strong) CALayer *frontLayer;
@property (nonatomic,readwrite,strong) CALayer *backLayer;


@end

BoxViewController.m

@implementation BoxViewController

const CGFloat kSize = 100;
const CGFloat kPanScale = 1./100;

-(CALayer *)layerWithColor:(UIColor *)color transform:(CATransform3D)transform
{
    CALayer *layer = [CALayer layer];
    layer.backgroundColor = [color CGColor];
    layer.bounds = CGRectMake(0, 0, kSize, kSize);
    layer.position = self.view.center;
    layer.transform = transform;
    [self.view.layer addSublayer:layer];
    return layer;
}

static CATransform3D MakePerspetiveTransform()
{
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1./200;
    return perspective;
}

-(void)viewDidLoad
{
    [super viewDidLoad];
    CATransform3D transform;
    transform = CATransform3DMakeTranslation(0, -kSize/2,0);
    transform = CATransform3DRotate(transform, M_PI_2, 1.0, 0, 0);
    self.topLayer = [self layerWithColor:[UIColor redColor] transform:transform];
    
    transform = CATransform3DMakeTranslation(0, kSize/2,0);
    transform = CATransform3DRotate(transform, M_PI_2, 1.0, 0, 0);
    self.bottomLayer = [self layerWithColor:[UIColor greenColor] transform:transform];
    
    transform = CATransform3DMakeTranslation(kSize/2,0,0);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
    self.rightLayer = [self layerWithColor:[UIColor blueColor] transform:transform];
    
    transform = CATransform3DMakeTranslation(-kSize/2,0,0);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
    self.rightLayer = [self layerWithColor:[UIColor cyanColor] transform:transform];

    transform = CATransform3DMakeTranslation(0,0,-kSize/2);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 0, 0);
    self.backLayer = [self layerWithColor:[UIColor yellowColor] transform:transform];
    
    transform = CATransform3DMakeTranslation(0,0,kSize/2);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 0, 0);
    self.frontLayer = [self layerWithColor:[UIColor magentaColor] transform:transform];
    
    self.view.layer.sublayerTransform = MakePerspetiveTransform();
    UIGestureRecognizer *g = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    [self.view addGestureRecognizer:g];
}

-(void)pan:(UIPanGestureRecognizer *)recognizer
{
    CGPoint translation = [recognizer translationInView:self.view];
    CATransform3D transform = MakePerspetiveTransform();
    transform = CATransform3DRotate(transform, kPanScale * translation.x, 0, 1, 0);
    transform = CATransform3DRotate(transform, -kPanScale * translation.x, 1, 0, 0);
    self.view.layer.sublayerTransform = transform;
}
@end

BoxViewController 展示了如何创建一个简单的方形并基于视角旋转。所有的图层都是使用layerWithColor:transform:方法创建的。注意,所有图层拥有相同的position。他们只能把方形经过平移和旋转的变形结果显示在屏幕上。

可以使用透视的sublayerTransform(一个针对所有子图层但对当前图层无效的变形)。这里不会谈及数学,不过3D变形矩阵的m34的位置应该设置为-1/EYE_DISTANCE。大多数情况下,2000个单位就可以做的很好了,不过你可以通过“缩放摄像机”来调整。

还可以通过设置position和zPosition(而不是平移)来构造方形,如以下代码所示

-(void)viewDidLoad
{
    [super viewDidLoad];
    CATransformLayer *contentLayer = [CATransformLayer layer];
    contentLayer.frame = self.view.layer.bounds;
    CGSize size = contentLayer.bounds.size;
    contentLayer.transform = CATransform3DMakeTranslation(size.width/2, size.height/2, 0);
    [self.view.layer addSublayer:contentLayer];
    self.contentLayer = contentLayer;
    
    self.topLayer = [self layerAtx:0 y:-kSize/2 z:0 color:[UIColor redColor] transform:MakeSideRotation(1,0,0)];
    ....
}

-(CALayer *)layerAtx:(CGFloat)x y:(CGFloat)y z:(CGFloat)z color:(UIColor *)color transform:(CATransform3D)transform
{
    CALayer *layer = [CALayer layer];
    layer.backgroundColor = [color CGColor];
    layer.bounds = CGRectMake(0, 0, kSize, kSize);
    layer.position = CGPointMake(x, y);
    layer.zPosition = z;
    layer.transform = transform;
    [self.contentLayer addSublayer:layer];
    return layer;
}
-(void)pan:(UIPanGestureRecognizer *)recognizer
{
    CGPoint translation = [recognizer translationInView:self.view];
    CATransform3D transform = MakePerspetiveTransform();
    transform = CATransform3DRotate(transform, kPanScale * translation.x, 0, 1, 0);
    transform = CATransform3DRotate(transform, -kPanScale * translation.x, 1, 0, 0);
    self.view.layer.sublayerTransform = transform;
}
你现在需要再其中插入CATransformLayer。如果只使用CALayer,那么zPosition只能用于计算图层显示顺序,而无法用来决定空间定位。这样就会使盒形看起来是扁平的。CATransformLayer支持zPosition并且不需要透视变形。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值