iOS 仿射变换CGAffineTransform详解

96
燃烧的大叔
2015.04.30 17:03* 字数 1083

UIView有CGAffineTransform类型的属性transform,它是定义在二维空间上完成View的平移,旋转,缩放等效果的实现。

初始化: CGAffineTransform  transform = CGAffineTransformIdentity;

CGAffineTransformIdentity是系统提供的一个常量,/* The identity transform: [ 1 0 0 1 0 0 ]. */(和原图一样的transform);

 CGAffineTransform transform  = CGAffineTransformMake(CGFloat a,CGFloat b,

CGFloat c,CGFloa td,CGFloat tx,CGFloat ty)

我们来解释下这里面参数的作用和变换的效果;

下面是原始的(默认的)transform

UIView默认的
参数结构

人后我们再来看它的计算公式:3 X 3矩阵合成得到(x`,y`,1)

(x`,y`,1)公式

矩阵算法公式:

算法公式

相信大家有所了解,我是懂了点点(数学是历史老师教的),看不到直观的东西。

接下来我们我们新建工程,在widow上建立两个同样大小位置相同的View,第一个为沙色,第二个是浅海蓝色,我修改第二个View的transform中a的值为0.2:CGAffineTransformMake(0.2,0,0,1,0,0);

图一是没有改变的原图,图二是改变之后的View,很明显的差异

原图
View2的transform变化后的图

我用3秒动画完成变换,发现它是两边开始往中间缩小,打印View的frame原来的{{100,100},{100,100}}变成了{{140,100},{20,100}}。我们来计算下是不是根据公式计算的。

根据变换的transform我们知道 a = 0.2 , b = 0 , c = 0 , d = 1 , t.x = 0 , t.y = 0;

                                                         x = 100 ,  y = 100

x` = ax + cy + t.x = 0.2 * 100 + 0 * 100 + 0 = 20

y` = bx + dy + t.y = 0 * 100 + 1 * 100 + 0 = 100

结合上面的图和下面的计算,瞬间明白了这是x按照a值进行了比例缩放,y按照d的值进行比列缩放,最重要的是缩放的过程中View的point(中心点)是不会改变的。

接着对b,c,t.x ,ty,进行深度研究发现:

x会跟着c的值进行拉伸(View的宽度是跟着改变),y会跟着b的值进行拉伸(View的高度跟着改变),要注意到的是c和b的值改变不会影响到View的point(center中心点)的改变。这是个很有意思的两个参数。

x会跟着t.x进行x做表平移,y会跟着t.y进行平移。这里的point(center)是跟着变换的。

下面是Apple整合的transform

平移

①根据本身的transform进行平移   CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)

②根据本身的transform后者另外的transform进行平移CGAffineTransformTranslate(CGAffineTransform t,CGFloat tx,CGFloat ty)

缩放

①根据本身的transform进行缩放 

CGAffineTransformMakeScale(CGFloat sx,CGFloat sy)

②根据本身的transform后者另外的transform进行缩放

 CGAffineTransformScale(CGAffineTransform t,CGFloat sx,CGFloat sy)

旋转

① 根据本身的transform进行旋转

 CGAffineTransformMakeRotation(CGFloat angle) (angle 旋转的角度)

②根据本身的transform后者另外的transform进行旋转

CGAffineTransformRotate(CGAffineTransform t,CGFloat angle)

恢复 :反向旋转

CGAffineTransformInvert(CGAffineTransform t)                                                                                           

合并

CGAffineTransformConcat(CGAffineTransform t1,CGAffineTransform t2)       

两个transform合并起来

倾斜:

这个使我们自己定义

-(CGAffineTransform) CGAffineTransformMakeShear(CGFloat x,CGFloat y)

{   CGAffineTransform transform = CGAffineTransformIdentity;

transform.c= -x;

transform.b= y;

returntransform;   }

layer.affineTransform = CGAffineTransformMakeShear(1,0);

评测:

①Bool CGAffineTransformIsIdentity(CGAffineTransform t)                   

 查看是不是默认的transform

②bool CGAffineTransformEqualToTransform(CGAffineTransform t1,CGAffineTransform t2)  

 比较两个transform是否相等

仿射矩阵应用:

①CGPointApplyAffineTransform(CGPoint point,CGAffineTransform t)  得到新的中心CGPoint

②CGSizeApplyAffineTransform(CGSize size,CGAffineTransform t)          得到新的size CGSize

③CGRectApplyAffineTransform(CGRect rect,CGAffineTransform t)        得到新的rect CGRect

放射矩阵一个常用的情形就是根据用户的手势来相应的改变视图的变换

UIPanGestureRecognizer                   位移

UIPinchGestureRecognizer                缩放

UIRotationGestureRecognizer          旋转

苹果官方的建议,要多次使用transform,最好是初始化一个CGAffineTransform,进行多次操作。

Note that you do not typically need to create affine transforms directly. If you want only to draw an object that is scaled or rotated, for example, it is not necessary to construct an affine transform to do so. The most direct way to manipulate your drawing—whether by movement, scaling, or rotation—is to call the functionsCGContextTranslateCTM,CGContextScaleCTM, orCGContextRotateCTM, respectively. You should generally only create an affine transform if you want to reuse it later.(原谅我英语不够好。)


Good lucky , every one!五一快乐!

iOS
Web note ad 1