简介
UIView 对象有一个 transform
属性,该属性可以使控件产生移动、缩放、旋转效果,其坐标系统采用的是二维坐标系,坐标原点为屏幕的左上角,向右为 x 轴正方向,向下为 y 轴正方向。
几种效果
- 移动
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
以初始位置为基准,在 x 轴方向上平移 x 单位,在 y 轴方向上平移y单位。
// 将图片左(100px)下(150px)方向移动
CGAffineTransform transform = CGAffineTransformMakeTranslation(-100, 150);
self.imageView.transform = transform;
可以结合视图动画进行变换,这样可以看到变换的过程。
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
在已有的 transform
基础上,增加 移动 效果。
self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, -50, 150);
- 缩放
// 以初始位置为基准,在x轴方向上缩放x倍,在y轴方向上缩放y倍
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
// 在已有的 transform 基础上,增加缩放效果
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
- 旋转
// 以初始位置为基准,将坐标系统旋转angle弧度(弧度=π/180×角度,M_PI弧度代表180角度)
CGAffineTransformMakeRotation(CGFloat angle)
// 在已有的transform基础上,增加旋转效果
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
- 初始 transform
控件的 transform 属性默认值为CGAffineTransformIdentity,通过设置该值可以将控件还原到最初的状态。
self.imageView.transform = CGAffineTransformIdentity;
- 反转变换效果
CGAffineTransformInvert(CGAffineTransform t)
接受一个 transform
,可以实现和参数相反的效果,比如放大3倍则会缩小为1/3,向x轴正方向平移100px效果则为向负方向平移100px。
CGAffineTransform transform = CGAffineTransformMakeScale(3, 3);
// 缩小为1/3
transform = CGAffineTransformInvert(transform);
self.imageView.transform = transform;
- 组合变换效果
CGAffineTransformConcat(CGAffineTransform t,CGAffineTransform t)
可以组合两种变换效果。
CGAffineTransform transform_A = CGAffineTransformMakeTranslation(0, 200);
CGAffineTransform transform_B = CGAffineTransformMakeScale(0.2, 0.2);
transform = CGAffineTransformConcat(transform_B, transform_A);
操作 transform
- 比较等同性
变换是可以比较的,我们可以判断两个变换是否相同。
// 判断变换是否是最初的状态
bool CGAffineTransformIsIdentity(CGAffineTransform t)
// 判断两个变换是否相同
bool CGAffineTransformEqualToTransform(CGAffineTransform t1, CGAffineTransform t2)
- 转换 point、size、rect
在进行变换之后,视图的 point、size、rect 都可能发生变化,我们可以通过特定的方法得到变换后的 point、size、rect。
// 得到转换后的point
CGPoint CGPointApplyAffineTransform(CGPoint point, CGAffineTransform t)
// 得到转换后的size
CGSize CGSizeApplyAffineTransform(CGSize size, CGAffineTransform t)
// 得到转换后的rect
CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t)
CGAffineTransform原理
CGAffineTransform 形变是通过 仿射变换矩阵 控制的,其中平移是矩阵相加,旋转与缩放则是矩阵相乘,CGAffineTransform 形变就是把二维形变使用一个三维矩阵来表示,系统提供了 CGAffineTransformMake
结构体来控制形变。
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)
该三维变换矩阵如下:
变换矩阵
通过变换矩阵左乘向量,将空间中的一个点集从一个坐标系变换到另一个坐标系中,计算方式如下:
矩阵相乘
计算结果
由此可知,
tx:用来控制在x轴方向上的平移
ty:用来控制在y轴方向上的平移
a:用来控制在x轴方向上的缩放
d:用来控制在y轴方向上的缩放
abcd:共同控制旋转
所以以下写法都是等同的。
- 移动:[ 1 0 0 1 tx ty ]
CGAffineTransformMakeTranslation(100, 100);
CGAffineTransformMake(1, 0, 0, 1, 100, 100);
- 缩放:[ sx 0 0 sy 0 0 ]
CGAffineTransformMakeScale(2, 0.5);
CGAffineTransformMake(2, 0, 0, 0.5, 0, 0);
- 旋转:[ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ]
CGAffineTransformMakeRotation(M_PI*0.5);
CGAffineTransformMake(cos(M_PI * 0.5), sin(M_PI * 0.5), -sin(M_PI * 0.5), cos(M_PI * 0.5), 0, 0);
- 最初:[ 1 0 0 1 0 0 ]
CGAffineTransformIdentity;
CGAffineTransformMake(1, 0, 0, 1, 0, 0);
简单应用
- 结合UIView动画使用
[UIView animateWithDuration:1.0 animations:^{
//缩放
CGAffineTransform transform = CGAffineTransformMakeScale(2, 2);
self.imageView.transform = transform;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
//回到最初
self.imageView.transform = CGAffineTransformIdentity;
} completion:nil];
}];
- 结合手势使用
// 点击手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
tap.numberOfTapsRequired = 2;
[self.testView addGestureRecognizer:tap];
//拖拽手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self.testView addGestureRecognizer:pan];
-(void)tapAction:(UITapGestureRecognizer *)tap{
if (CGAffineTransformIsIdentity(self.testView.transform)) {
[UIView animateWithDuration:0.5 animations:^{
self.testView.transform = CGAffineTransformScale(self.testView.transform, 1.3, 2);
}];
}
else{
[UIView animateWithDuration:0.5 animations:^{
self.testView.transform = CGAffineTransformIdentity;
}];
}
}
-(void)panAction:(UIPanGestureRecognizer *)pan{
//获取手势位置
CGPoint position = [pan translationInView:self.testView];
//通过 CGAffineTransformTranslate 获取 新的transform
self.testView.transform = CGAffineTransformTranslate(self.testView.transform, position.x, position.y);
//将增加置为 0
[pan setTranslation:CGPointZero inView:self.testView];
}
总结
变换属性可以控制视图进行移动、缩放、移动,结合视图动画或者手势可以实现一些简单的动画效果。变换会真实的改变动画的 frame、size、rect,可以通过特定的方法变换这些值。CGAffineTransform 形变是通过 仿射变换矩阵 控制的,其中平移是矩阵相加,旋转与缩放则是矩阵相乘。