三.iOS核心动画 - 关于图层几何(frame,bounds,transform,position)

引言

关于UIView的布局有一个经常被问到的问题,frame和bounds有什么区别,同样CALayer也有frame和bounds这两个属性,还有一个与UIView的center对应的position属性,本篇博客我们就来详细的探讨一下图层中的frame和bounds到底有什么区别?以及为什么在UIView中中心点使用了center而图层中使用了position?

图层几何属性

图层的布局

frame其实代表的是外部坐标系,也就是在父图层上占据的空间。

bounds则是内部坐标系,它的x和y总是0。

position(视图中的center)代表了相对于父图层anchorPoint(锚点)所在位置。

上面图片展示了一个白色的View添加到了黑色View上。

对于视图来说它的frame,bounds,和center分别是

frame = {10,10,50,30}

bounds = {0,0,50,30}

center = {35,25}

对于图层来说也是一样的:

frame = {10,10,50,30}

bounds = {0,0,50,30}

position = {35,25}

到目前为止这些属性看起来都是一样的,事实上视图的frame,bounds,center这三个属性仅仅是存取方法。当我们操作视图的frame时,实际上是在改变位图视图下方CALayer的frame。

frame属性其实并不是一个非常明确的属性,而是一个虚拟属性,是根据bounds,position和transform共同计算而来的,所以当其中任何一个发生改变时,frame都会发生改变。

当图层做旋转或者缩放的变换时,frame实际上是覆盖在图层变换之后的整个轴对齐的矩形区域,所以frame的宽高并不总是等于bounds的宽高,如下图所示:

图层发生了旋转之后,它的bounds和position没有任何变化。

但是frame是绿色边框的矩形区域,不管是x,y还是width,height都发生了变化。

图层的anchorPoint(锚点)

上面提到了anchorPoint属性,图层的anchorPoint通过position来控制它的frame属性,我们可以把anchorPoint当做是移动图层的把柄。

anchorPoint也使用单位坐标,默认来说它位于图层的中点{0,0},所以图层将会以这个点为中心放置,而UIView的anchorPoint属性没有暴漏出来,所以对于视图来说它的锚点总是中心点,因此视图的position也就可以被称之为center。

但是图层的anchorPoint是可以被移动的,比如我们把它的anchorPoint调整到左上角{0,0},如图所示(虚框为调整后的图层显示):

​​​​​​​

图层的坐标系

图层在图层树当中也是相对父层级按层级关系来放置,这一点和视图是一样的。

当父图层发生移动和变化时,所有的子图层也会跟随移动和变化。

这样确实很方便,但是有的时候我们还是需要知道一个图层的绝对位置,或者是一个图层相对另外一个图层的位置。

和视图一样CALayer也提供了一系列的图层间坐标转换的方法:

    open func convert(_ p: CGPoint, from l: CALayer?) -> CGPointopen func convert(_ p: CGPoint, to l: CALayer?) -> CGPointopen func convert(_ r: CGRect, from l: CALayer?) -> CGRectopen func convert(_ r: CGRect, to l: CALayer?) -> CGRect

这些方法,可以把定义在一个图层坐标系下的点或者矩形区域转换成另一个图层坐标系吓得点或者矩形区域。

图层的Z坐标

CALayer实际上存在于一个三维空间当中,所以它还有另外两个特殊的属性,zPosition和anchorPointZ,两个都是在z轴上描述图层位置的浮点类型。

不过zPosition属性其实并不常用,它最直观的功能就是修改图层的显示顺序,通常来讲图层是根据它们子图层的sublayers出现的顺序来绘制的,也就是后绘制的图层会覆盖先绘制的图层。但是我们可以通过修改zPosition,来调整图层的显示顺序,当我们增加这个值的时候它就可以显示到所有小于它的zPosition图层的前面。

举个例子,我们创建两个图层:

        let layer = CALayer()layer.backgroundColor = UIColor.white.cgColorlayer.frame = CGRect(x: 0, y: 0, width: 226, height: 137)layer.position = self.view.centerself.view.layer.addSublayer(layer)let redLayer = CALayer()redLayer.backgroundColor = UIColor.red.cgColorredLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 100)redLayer.position = CGPoint(x: self.view.center.x + 100, y:  self.view.center.y + 100)self.view.layer.addSublayer(redLayer)

在没有修改zPosition的情况下显示如下:

当我们把白色图层的zPosition设置为1时:

        let layer = CALayer()layer.zPosition = 1layer.backgroundColor = UIColor.white.cgColorlayer.frame = CGRect(x: 0, y: 0, width: 226, height: 137)layer.position = self.view.centerself.view.layer.addSublayer(layer)

效果如下:

我们发现通过修改zPosition白色的图层已经显示在了红色图层之上。

但是有个问题需要注意,当我们处理图层的点击事件时,仍然还是按照图层的添加顺序来处理,通过修改zPosition并不能改变图层的响应顺序。不过我们不是说图层不关心响应链事件吗?下面就来说明这件事儿。

图层的点击事件

CALayer确实不关心响应链,但是它有一些列的方法来处理事件

判断触摸点是否在图层内

open func contains(_ p: CGPoint) -> Bool

获取触摸点所在图层

open func hitTest(_ p: CGPoint) -> CALayer?

使用contains方法判断被点击的图层:

    var whiteLayer: CALayer!var redLayer: CALayer!override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = .blacklet layer = CALayer()layer.backgroundColor = UIColor.white.cgColorlayer.frame = CGRect(x: 0, y: 0, width: 226, height: 137)layer.position = self.view.centerself.view.layer.addSublayer(layer)self.whiteLayer = layerlet redLayer = CALayer()redLayer.backgroundColor = UIColor.red.cgColorredLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 100)redLayer.position = CGPoint(x: self.view.center.x + 100, y:  self.view.center.y + 100)self.view.layer.addSublayer(redLayer)self.redLayer = redLayer}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let point = touches.first?.location(in: self.view)let layerPoint = self.whiteLayer.convert(point!, from: self.view.layer)if self.whiteLayer.contains(layerPoint) {print("点击了白色图层")}let redLayerPoint = self.redLayer.convert(point!, from: self.view.layer)if self.redLayer.contains(redLayerPoint) {print("点击了红色图层")}}

点击了白色图层

点击了红色图层

可以看见确实可以处理点击事件。

使用hitTest方法处理点击图层:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let point = touches.first?.location(in: self.view)let layer = self.view.layer.hitTest(point!)if layer == self.whiteLayer {print("点击了白色图层")} else if layer == self.redLayer {print("点击了红色图层")}}

点击了白色图层

点击了红色图层

之前提到的修改zPosition属性可以修改图层的显示顺序,但是不能改变事件的传递顺序也可以在这里进行验证。

总结

本篇博客主要说明了图层的几何结构,包括它的frame,position和bounds以及三者的关系。图层的点击事件,后面的博客会继续介绍一些图层的外表特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/33013.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python酷库之旅-第三方库openpyxl(07)

目录 一、 openpyxl库的由来 1、背景 2、起源 3、发展 4、特点 4-1、支持.xlsx格式 4-2、读写Excel文件 4-3、操作单元格 4-4、创建和修改工作表 4-5、样式设置 4-6、图表和公式 4-7、支持数字和日期格式 二、openpyxl库的优缺点 1、优点 1-1、支持现代Excel格式…

十大经典排序算法——选择排序和冒泡排序

一、选择排序 1.基本思想 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据全部排完。 2.直接选择排序 (1) 在元素集合arr[i] — arr[n - 1]中选择关键妈的最大&#xff08;小…

高考十字路口:24年考生如何权衡专业与学校的抉择?

文章目录 每日一句正能量前言专业解析理工科专业商科专业人文社科专业艺术与设计专业个人经验与思考过程结论 名校效应分析名校声誉与品牌效应资源获取学术氛围就业优势个人发展结论 好专业和好学校的权衡个人职业目标行业需求教育质量资源和机会学术氛围就业优势经济和地理位置…

嵌入式学习——数据结构(单向无头链表)——day46

1. 数据结构 1.1 定义 数据结构是指计算机中数据的组织、管理和存储方式。它不仅包括数据元素的存储方式&#xff0c;还包括数据元素之间的关系&#xff0c;以及对数据进行操作的方法和算法。数据结构的选择和设计直接影响算法的效率和程序的性能&#xff0c;是计算机科学与编…

说一说三大运营商的流量类型,看完就知道该怎么选运营商了!

说一说三大运营商的流量类型&#xff0c;看完就知道该怎么选运营商了&#xff1f;目前三大运营商的流量类型大致分为通用流量和定向流量&#xff0c;比如&#xff1a; 中国电信&#xff1a;通用流量定向流量 电信推出的套餐通常由通用流量定向流量所组成&#xff0c;通用流量…

【Python时序预测系列】基于LSTM实现单变量时序序列多步预测(案例+源码)

这是我的第307篇原创文章。 一、引言 单站点单变量输入单变量输出多步预测问题----基于LSTM实现。 单输入就是输入1个特征变量 单输出就是预测出1个标签的结果 多步就是利用过去N天预测未来M天的结果 二、实现过程 2.1 读取数据集 # 读取数据集 data pd.read_csv(data.c…

HTML5文旅文化旅游网站模板源码

文章目录 1.设计来源文旅宣传1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 文旅之行界面演示1.5 文旅之行文章内容界面演示1.6 关于我们界面演示1.7 文旅博客界面演示1.8 文旅博客文章内容界面演示1.9 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目…

笔记本电脑屏幕模糊?6招恢复屏幕清晰!

在数字化时代的浪潮中&#xff0c;笔记本电脑已成为我们生活、学习和工作中不可或缺的一部分。然而&#xff0c;当那曾经清晰明亮的屏幕逐渐变得模糊不清时&#xff0c;无疑给我们的使用体验蒙上了一层阴影。屏幕模糊不仅影响视觉舒适度&#xff0c;更可能对我们的工作效率和眼…

【AI大模型】驱动的未来:穿戴设备如何革新血液、皮肤检测与营养健康管理

文章目录 1. 引言2. 现状与挑战3. AI大模型与穿戴设备概述4. 数据采集与预处理4.1 数据集成与增强4.2 数据清洗与异常检测 5. 模型架构与训练5.1 高级模型架构5.2 模型训练与调优 6. 个性化营养建议系统6.1 营养建议生成优化6.2 用户反馈与系统优化 7. 关键血液成分与健康状况评…

WIN Semis揭幕耐湿砷化镓pHEMT技术

​犹如为无线通信领域注入了一股清新的活力。这项技术不仅支持E频带&#xff0c;更在晶圆级上筑起了一道坚固的防潮屏障&#xff0c;满足了对严苛环境条件的bHAST挑战。今日&#xff0c;WIN半导体公司正式公布了0.1m pHEMT技术PP10-29的测试版&#xff0c;预示着通信领域的新篇…

ansible 任务块以及循环

任务块 可以通过block关键字&#xff0c;将多个任务组合到一起可以将整个block任务组&#xff0c;一起控制是否要执行 # 如果webservers组中的主机系统发行版是Rocky&#xff0c;则安装并启动nginx [rootpubserver ansible]# vim block1.yml --- - name: block tasks hosts…

ROS2从入门到精通4-4:局部控制插件开发案例(以PID算法为例)

目录 0 专栏介绍1 控制插件编写模板1.1 构造控制插件类1.2 注册并导出插件1.3 编译与使用插件 2 基于PID的路径跟踪原理3 控制插件开发案例(PID算法)常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和…

Go 如何使用指针灵活操作内存

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

爬虫笔记14——爬取网页数据写入MongoDB数据库,以爱奇艺为例

下载MongoDB数据库 首先&#xff0c;需要下载MongoDB数据库&#xff0c;下载的话比较简单&#xff0c;直接去官网找到想要的版本下载即可&#xff0c;具体安装过程可以看这里。 pycharm下载pymongo库 pip install pymongo然后在在python程序中我们可以这样连接MongoDB数据库…

IPD推行成功的核心要素(十三)IPD产品开发流程让企业正确地做事情

一个公司能否成功&#xff0c;取决于它适应市场需求和竞争环境变化的速度。公司需要不断创新&#xff0c;以符合客户期望并保持相关性。这意味着需要更快速地推出新产品和改进产品。简化的产品开发流程能够支持快速开发周期&#xff0c;帮助公司领先于市场&#xff0c;用优秀的…

植物大战僵尸杂交版2.1版本终于来啦!游戏完全免费

在这个喧嚣的城市里&#xff0c;我找到了一片神奇的绿色世界——植物大战僵尸杂交版。它不仅是一款游戏&#xff0c;更像是一扇打开自然奥秘的窗户&#xff0c;让我重新认识了植物和自然的力量。 植物大战僵尸杂交版最新绿色版下载链接&#xff1a; https://pan.quark.cn/s/d6…

MySQL的综合运用

MySQL版的葵花宝典&#xff0c;欲练此功&#xff0c;挥刀自。。。呃&#xff0c;&#xff0c;&#xff0c;说错了&#xff0c;是先创建两个表&#xff0c;分别是location表和store_info表 示例表为location表和store_info表&#xff0c;如下图所示&#xff1a; 操作一&#xf…

【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;STL-> map与set &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀AVL树 &#x1f4d2;1. AVL树…

JavaSE (Java基础):运算符

3 运算符 3.1 二元运算符 为什么下面这段代码中最后的语句中b元素要加&#xff08;double&#xff09;呢&#xff1f; 因为要计算10/40的话&#xff0c;他们都是int类型的在计算机中会取整&#xff0c;而计算机取整一般都是直接舍去小数点后面的数字&#xff0c;那么就会返回0&…

VScode基本使用

VScode下载安装&#xff1a; Visual Studio Code - Code Editing. Redefined MinGW的下载安装&#xff1a; MinGW-w64 - for 32 and 64 bit Windows - Browse Files at SourceForge.net x86是64位处理器架构&#xff0c;i686是32为处理器架构。 POSIX和Win32是两种不同的操…