三.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;是计算机科学与编…

uniapp 低功耗蓝牙BLE分包

ble.js // 分包写入蓝牙async sendWriteBLECharacteristicValue(deviceId,serviceId,writeCharacteristicId,readCharacteristicId,buffer,success, // 成功回调failure, // 失败回调) {const offset 500; // 偏移量let pos 0; // 位置let bytes buffer.byteLength; // 总字…

.env 文件详解(vite)

.env.development 开发环境.env.production 正式环境.env.test 测试环境 .env文件内容&#xff1a; 开发环境 # 当前环境&#xff0c;VITE_ 开头 VITE_NODE_ENV development # 请求基地址 VITE_BASE_URL /api # 本地代理目标地址&#xff0c;在proxy里面target里面用 VITE…

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

说一说三大运营商的流量类型&#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 源码目…

Spring Boot框架原理及应用详解(三)

本系列文章简介: 在当今的软件开发世界中,快速迭代、高效开发以及易于维护成为了开发者们不断追求的目标。Spring Boot作为Spring框架的一个子项目,自其诞生以来就凭借其“约定大于配置”的理念和自动配置的特性,迅速在Java开发社区中获得了广泛的关注和认可。它简化了Spri…

QT 中ListView和ListWidget有什么区别

ListView和ListWidget在Qt框架中都是用于显示列表数据的控件&#xff0c;但它们在使用方法和特性上存在一些明显的差异。以下是关于它们用法不一样的地方的详细分析&#xff1a; 数据管理方式&#xff1a; ListView&#xff1a;使用QAbstractItemModel数据模型来管理和显示列表…

electron录制应用-自由画板功能

功能 录屏过程中的涂画功能允许用户在录制屏幕操作的同时&#xff0c;实时添加注释和高亮显示&#xff0c;以增强信息的传达和观众的理解。 效果 electron录制-添加画布 代码实现 1、利用HTML5的Canvas元素实现一个自由涂画的功能&#xff0c;允许用户在网页上进行手绘创作。…

笔记本电脑屏幕模糊?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;预示着通信领域的新篇…

React学习(一)

React的详细解析: 1. React的起源与背景 React起源于Facebook的内部项目&#xff0c;旨在解决市场上JavaScript MVC框架的不足之处。React的早期原型被称为“FaxJS”&#xff0c;由Facebook工程师Jordan Walke开发&#xff0c;深受XHP&#xff08;一个简单的PHP HTML组件框架…

ansible 任务块以及循环

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

墨刀原型工具-小白入门篇

墨刀原型工具-小白入门篇 简介 随着互联网的发展和用户体验的重要性越来越受到重视&#xff0c;原型设计逐渐成为了产品设计中的重要环节。墨刀作为一款原型设计工具&#xff0c;以其简洁、易用的特点&#xff0c;受到了很多设计师的喜爱。本文将介绍墨刀原型工具的基本使用方…

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的主页」…