原文:
这里对CGAffineTransform和CATransform3D的使用做个记录,比较简单的实现2D和3D的旋转,位移,缩放,锚点相关的有一些问题后续更新
CGAffineTransform是作用于View的主要为2D变换,而CATransform3D主要作用于Layer,为3D变换使用,这两种变换可以转换
CGAffineTransform
cgAffineTransform本身是一个仿射变换矩阵
1.矩阵的基本知识:
struct CGAffineTransform
{
CGFloat a, b, c, d;
CGFloat tx, ty;
};
CGAffineTransform CGAffineTransformMake( CGFloat a,CGFloat b,CGFloat c,CGFloat d,CGFloat tx,CGFloat ty);
为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准。 所以所有的变化都由前两列完成。
以上参数在矩阵中的表示为:
|a b 0|
|c d 0|
|tx ty 1|
运算原理:原坐标设为(X,Y,1);
|a b 0|
[X,Y, 1] |c d 0| = [aX + cY + tx bX + dY + ty 1] ;
| tx ty 1|
通过矩阵运算后的坐标[aX + cY + tx bX + dY + ty 1],我们对比一下可知:
设a=d=1, b=c=0.
[aX + cY + tx bX + dY + ty 1] = [X + tx Y + ty 1];
可见,这个时候,坐标是按照向量(tx,ty)进行平移,其实这也就是函数
CGAffineTransform CGAffineMakeTranslation(CGFloat tx,CGFloat ty)的计算原理。
设b=c=tx=ty=0.
[aX + cY + tx bX + dY + ty 1] = [aX dY 1];
可见,这个时候,坐标X按照a进行缩放,Y按照d进行缩放,a,d就是X,Y的比例系数,其实这也就是函数
CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)的计算原理。a对应于sx,d对应于sy。
第三种: 设tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ。
[aX + cY + tx bX + dY + ty 1] = [Xcosɵ - Ysinɵ Xsinɵ + Ycosɵ 1] ;
可见,这个时候,ɵ就是旋转的角度,逆时针为正,顺时针为负。其实这也就是函数
CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)的计算原理。angle即ɵ的弧度表示。
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI) //旋转 - (IBAction)doRotate:(id)sender { // transformItem.transform = CGAffineTransformIdentity; // transformItem.layer.anchorPoint = CGPointMake(1,0); // transformItem.center = CGPointMake(CGRectGetWidth(transformItem.bounds), 0.0); // transformItem.center = CGPointMake(transformItem.center.x-transformItem.frame.size.width*0.5, transformItem.center.y-transformItem.frame.size.height*0.5); [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ // transformItem.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90)); transformItem.transform = CGAffineTransformRotate(transformItem.transform, DEGREES_TO_RADIANS(-90)); } completion:^(BOOL finished){ }]; } //缩放 - (IBAction)doScale:(id)sender { CGAffineTransform tr = CGAffineTransformScale(transformItem.transform, 2, 2); CGFloat h = transformItem.frame.size.height; [transformItem.layer setAnchorPoint:CGPointMake(0, 1)]; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ // transformItem.transform = CGAffineTransformScale(transformItem.transform, 0.5, 0.5); transformItem.transform = tr; // transformItem.center = CGPointMake(0,h); } completion:^(BOOL finished){ }]; } //位移 - (IBAction)doTranslate:(id)sender { [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ transformItem.transform = CGAffineTransformTranslate(transformItem.transform,100, 0); } completion:^(BOOL finished){ }]; }
CATransform3D
CATransform3D也是个矩阵,多了一些切变和Z轴的值,这里通过CABasicAnimation来实现
#define ANIM_ROTATE @"animationRotate" #define ANIM_FALLING @"animationFalling" #define ANIM_GROUP @"animationFallingRotate" - (IBAction)do3dRotate:(id)sender { CAAnimation* myAnimationRotate = [self animationRotate]; [transformItem.layer addAnimation:myAnimationRotate forKey:ANIM_ROTATE]; } -(IBAction)do3dFalling:(id)sender { CAAnimation* myAnimationFalling = [self animationFallingDown]; [transformItem.layer addAnimation:myAnimationFalling forKey:ANIM_FALLING]; } -(IBAction)do3dShrink:(id)sender { CAAnimation* myAnimationShrink = [self animationShrink]; [transformItem.layer setAnchorPoint:CGPointMake(1, 1)]; [transformItem.layer addAnimation:myAnimationShrink forKey:ANIM_FALLING]; } //- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag //{ // //这边为什么是nil? :( // NSLog(@"anim = %@", [m_pMyImageView.layer valueForKey:ANIM_GROUP]); //#if 1 // //识别动画 // //?debug发现两者的地址不一样,这个问题很纠结 // if ([anim isEqual:m_pGroupAnimation])//[m_pMyImageView.layer valueForKey:ANIM_GROUP]) // { // NSLog(@"removeFromSuperview..."); // [m_pMyImageView removeFromSuperview]; // [m_pMyImageView release]; // // } //#else // //这种方法,虽然能解决方法,但是处理多个CAAnimationGroup动画或者CAAnimation动画时,就不能有效处理,方法待定 // //这组动画结束,移除视图 // if ([anim isKindOfClass:[CAAnimationGroup class]]) // { // //这边为什么是nil? :( // NSLog(@"anim = %@", [m_pMyImageView.layer valueForKey:ANIM_GROUP]); // // [m_pMyImageView removeFromSuperview]; // [m_pMyImageView release]; // // } //#endif //} - (CAAnimation *)animationShrink { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.toValue = [NSNumber numberWithDouble:2.0]; animation.duration = 3.0; animation.autoreverses = YES; animation.repeatCount = FLT_MAX; //"forever" animation.removedOnCompletion = NO; //设置动画代理 animation.delegate = self; return animation; } - (CAAnimation *)animationFallingDown { //falling down animation: CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"]; animation.duration = 5.0; animation.autoreverses = NO; animation.removedOnCompletion = NO; animation.repeatCount = FLT_MAX; //"forever" animation.fromValue = [NSNumber numberWithInt: 0]; animation.toValue = [NSNumber numberWithInt: 1024]; //设置动画代理 animation.delegate = self; return animation; } - (CAAnimation *)animationRotate { // rotate animation CATransform3D rotationTransform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0.0); CABasicAnimation* animation; animation = [CABasicAnimation animationWithKeyPath:@"transform"]; animation.toValue = [NSValue valueWithCATransform3D:rotationTransform]; animation.duration = 1.5; animation.autoreverses = NO; animation.cumulative = YES; animation.repeatCount = FLT_MAX; //"forever" //设置开始时间,能够连续播放多组动画 animation.beginTime = 0.5; //设置动画代理 animation.delegate = self; return animation; }