在使用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做修改都是有顺序的,这一点与矩阵乘法一致,顺序会影响结果。

iOS Transform坐标变化的更多相关文章

  1. transform图形变化

    <!DOCTYPE HTML> <head> <meta charset = "utf-8"> <title>canvas</ ...

  2. Web开发者和设计师必须要知道的 iOS 8 十个变化

    原文出处: mobilexweb   译文出处:罗磊(@罗罗磊磊)   欢迎分享原创到伯乐头条 喜大普奔,喜极而泣,喜当爹,随着iPhone 6和iPhone 6 plus的上市,ios 8终于在上周 ...

  3. iOS 火星坐标相关整理及解决方案汇总(转)

    这几天在处理定位相关的代码,彻彻底底的被火星坐标恶心到了. 恶心列表 从 CLLocationManager 取出来的经纬度放到 mapView 上显示,是错的! 从 CLLocationManage ...

  4. 百度地图 iOS SDK - 坐标转换方法

    百度地图 Android SDK 要么 iOS SDK 或各种 API 工具产品,我们使用百度自己的加密坐标系. 员在使用过程中,位置点都是通过 GPS 或者其它途径获取的.所以与百度地图所使用的坐标 ...

  5. iOS 通知的变化ios9-10,新功能展示

    二.新功能展示 1  使用 /iOS通知新功能玩法 2.  全面   iOS10里的通知与推送详情 一.变化 四.Notification(通知) 自从Notification被引入之后,苹果就不断的 ...

  6. iOS transform属性的使用

    1.transform属性 在iOS开发中,通过transform属性可以修改UIView对象的平移.缩放比例和旋转角度,常用的创建transform结构体方法分两大类 (1) 创建“基于控件初始位置 ...

  7. IOS transform的使用(移动,放大,旋转)

    @interface ViewController () - (IBAction)up; - (IBAction)big ; - (IBAction)leftRotate ; @property (n ...

  8. iOS 定位坐标不准确的相关整理及解决方案汇总

    这几天处理定位相关的代码,彻彻底底的被火星坐标恶心到了. 恶心列表 从 CLLocationManager 取出来的经纬度放到 mapView 上显示,是错的! 从 CLLocationManager ...

  9. iOS transform解决连续多次旋转缩放,实现图片旋转缩放效果

    一.需求 实现imageView的缩放旋转效果,一般有两种方式: 1.底层加scrollview,利用scrollview的属性实现.(推荐这种,这是我比较后发现的,手势做缩放旋转会有点弊端) 2.利 ...

随机推荐

  1. Linux终端 terminal

    终端 一个可以进行人机交互的界面 物理终端 设备终端:键盘.鼠标.显示器 终端类型 控制台终端: /dev/console 串行终端:/dev/ttyS# 虚拟终端:tty:teletypewrite ...

  2. 蒲公英 &#183; JELLY技术周刊 Vol.26: 请问您这个月要来点肝么?

    蒲公英 · JELLY技术周刊 Vol.26 今年的十月,不知道大家在 TODO List 上新增了多少条目准备尝鲜,你可能已经准备了 Vue3.Webpack5 以及 React v17.0 RC, ...

  3. 分布式消息系统之Kafka集群部署

    一.kafka简介 kafka是基于发布/订阅模式的一个分布式消息队列系统,用java语言研发,是ASF旗下的一个开源项目:类似的消息队列服务还有rabbitmq.activemq.zeromq:ka ...

  4. 【Flutter 混合开发】与原生通信-BasicMessageChannel

    Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...

  5. git学习(五) git diff操作

    git diff操作 git diff用于比较差异: git diff 不加任何参数 用于比较当前工作区跟暂存区的差异 git diff --cached 或者--staged 对比暂存区(git a ...

  6. Stimulsoft报表工具中属性表达式设置属性表达式

    Stimulsoft仪表工具实现所需的数据可视化和自己的信息图表.该产品能够应用必要的过滤器和排序,汇总数据,执行任何复杂度的计算.该产品的优势在于其多功能性-能够为您的业务,财务,销售,行业等任何领 ...

  7. Redis---05主从复制(一般模式)

    一.什么是主从复制 主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主 二.用处 读写分离,性能扩展:容灾快速恢复 三.主从配置 1 ...

  8. CVE-2017-6090&msf的基本使用(一)

    渗透环境的搭建 phpcollab的下载:phpCollab-v2.5.1.zip 解压到www目录,给www目录权限,因为这个漏洞需要写的权限 chmod 777 wwww 基本环境 配置 mysq ...

  9. Spring源码知识概览

    目录 Spring知识总览 1.1 IOC 1.2 Spring中重要接口概览 Spring知识总览 1.1 IOC IOC是控制反转,是一种思想 DI是依赖注入,是控制翻转的一种实现 Spring的 ...

  10. 4G DTU的使用方法和应用领域

    4G DTU是一种数据传输单元,通俗理解就是,用来传输数据的一种硬件.既然是用来传输数据的,那就能将它视为一个管道,也就是说,指令同过它传给设备,而管道是不对这些指令做出响应的. 4G DTU如何使用 ...