关于ios:iOS-Transform坐标变化

2次阅读

共计 3040 个字符,预计需要花费 8 分钟才能阅读完成。

在应用 CGContext 时,因为 Quartz 2D 与 UIKit 坐标不统一,所以须要对 context 进行再一次的变动,达到预期的成果。

1. 不同坐标原点介绍

在 Quartz 2D 中,坐标原点在画布的左下角,而 UIKit 中,与屏幕坐标统一,以左上角为坐标原点。

如果以(0,0)点为原点绘制 F,那么在不同的坐标系就会取得如下的后果。

2. Quartz 2D 与 UIKit 坐标系转化

2.1 UIImage 绘制

在 iOS 的 UI 开发中,以 UIImage 为例,绘制一张图片,设置 image 的 frame 为(0, 0, 320, 320),会失去上图右的画面。

如果应用如下代码读取 Context 的 transform,能够看到这个 transform 并不是单位矩阵。

*CGRect frame = CGRectMake(0.0, 0.0, 720, 1280);

UIGraphicsBeginImageContext(frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform contextTransform = CGContextGetCTM(context);;*

这里的 transform 设置会使 Quartz 2D 与 UIKit 的坐标原点重合,也是不便了 UIKit 中控件的绘制,坐标系变动能够参考下图。

这也是为什么如果间接在获取到的 context 上调用 CGContextDrawImage 时会失去一个反转的图像的起因。

但如果应用 UIImage 的 drawInRect 办法,文档是这么写的:
*Instance Method
draw(in:)
Draws the entire image in the specified rectangle, scaling it as necessary to fit.
Declaration
func draw(in rect: CGRect)
Parameters
rect
The rectangle (in the coordinate system of the graphics context) in which to draw the image.
Discussion
This method draws the entire image in the current graphics context, respecting the image’s orientation setting. In the default coordinate system, images are situated down and to the right of the origin of the specified rectangle. This method respects any transforms applied to the current graphics context, however.
This method draws the image at full opacity using the CGBlendMode.normal blend mode.*

也就是说,UIImage 绘制时应用的坐标还是 UIKit 的外部坐标,所以并不需要对坐标系做任何变动,就能够绘制出与 rect 地位雷同的图片了,当然这个办法也会依据图片的朝向绘制。

2.2 CGContextDrawImage 绘制

在扭转 context 的 transform 时,实际上在变动的其实是坐标系自身。

而调用绘制办法时,应用的还是坐标系外部坐标,所以当咱们想基于获取到的 context 绘制一个如 UIKit 显示的图片,咱们还须要对绘制前的坐标系做调整。

// Y 轴翻转
CGContextScaleCTM(context, 1, -1);

// 须要图片原点与左上角对齐,还需 Y 轴向下平移图片高度
CGContextTranslateCTM(context, 0, -imageSize.height);

// 绘制图片
CGContextDrawImage(context, frame, image.CGImage);

3 transform 锚点变动

比方图片编辑页面,咱们常常能碰到应用手势对图片进行缩放旋转位移等变动,之后生成一张新的图片。

依据不同的手势回调,咱们能够批改 view.transform,使得界面上的 view 产生与手势相应的变动。

在这里,UIKit 为了不便咱们批改 UI 界面,view 的 transform 是以 view 的 center 为锚点的。

UIView 的 transform 外面的形容是应用 center 来批改 position。

Use this property to scale or rotate the view’s frame rectangle within its superview’s coordinate system. (To change the position of the view, modify the center property instead.) The default value of this property is CGAffineTransformIdentity.

而很多其余的办法在调用时,transform 都须要以左上角为锚点,所以这里有须要做一次转化,锚点影响如下图。

在 UI 界面的批改中,咱们能够应用缩放和旋转手势的回调值间接批改 view 的 transform,以及位移的回调来批改 center,便能够达到咱们预期的成果。但这个 transform 无奈应用在 context 的绘制上,因为坐标系的变动,是以原点为锚点来做的。

所以针对 context 现有坐标系的地位,锚点在左上角,须要进行一次 transform 的批改。

依据上图也能够看出,锚点只会对地位信息产生影响,并不会扭转缩放和旋转。

UIImage *image; // 初始化图片

UIView *view;// 利用变动的 view,view 的 size 跟 image 要统一保障缩放比例是对的。

*CGAffineTransform transform = view.transform;

CGSize imageSize = image.size;
transform.tx = view.center.x;
transform.ty = view.center.y;
transform = CGAffineTransformTranslate(transform, -imageSize.width * 0.5, -imageSize.height * 0.5);*

其中 tx,ty 为锚点在坐标系的地位

以后的锚点在视图的中心点,咱们须要扭转到视图的左上角,这样就能够和坐标系原点重合。其中 (imageSize.width 0.5, imageSize.height 0.5) 为锚点在图片中的地位,此时 transform 为锚点在视图左上角时的变动矩阵。

4. 组合 Transform

在 CGContext 上想得到上图两头的后果,不仅须要利用放大 1 / 2 和旋转 45 度的变动,还须要调整。

之前说过 CGContext 利用旋转是利用在坐标系上,跟视图利用旋转的形式是本身坐标系是统一的。所以当间接获取到的 CGContext,优化后的坐标系也是左上角为原点时,能够间接再 CGContext 上利用咱们计算出的 transform。

之后还是因为坐标系绘制是以本身坐标系计算,再做一轮坐标系的翻转和位移来失去最初的后果,相似下图的操作。

这里须要留神,每一次新的变动都是在之前变动的根底上,所以无论是 view 还是对 context 的 transform 做批改都是有程序的,这一点与矩阵乘法统一,程序会影响后果。

正文完
 0