四.iOS核心动画 - 图层的视觉效果

news2024/11/20 13:37:50

引言

在前几篇博客中我们讨论了图层的frame,bounds,position以及让图层加载图片。但是图层事实上不仅可以显示图片,或者规则的矩形块,它还有一系列内建的特性来创建美丽优雅的页面元素。在这篇博客中我们就来探索一下CALayer的视觉效果。

视觉效果

图层的一些基础视觉效果其实在我们的日常开发过程中也经常会用到,比如圆角,边框,阴影,还有一些不常用的效果比如蒙版,下面我们就来一一讨论一下。

图层圆角

近些年圆角矩形几乎成为了主流的审美特性,不管是图标,还是页面元素,甚至文本输入框也都是按照圆角矩形来设计的。

CALayer有一个叫做cornerRadius的属性来控制着图层的圆角曲率,它是一个浮点型默认为0也就是直角。通过修改它为一个大于0的值,可以实现CALayer的圆角,默认情况下这个值只影响本图层的背景颜色,而不影响图层的背景图片或者是子图层,不过如果把maskesToBounds设置成为YES的话,图层里面的所有东西都会被截取。

未设置masksToBounds属性:

        let whiteLayer = CALayer()
        whiteLayer.backgroundColor = UIColor.white.cgColor
        whiteLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        whiteLayer.position = self.view.center
        whiteLayer.cornerRadius = 20.0
        self.view.layer.addSublayer(whiteLayer)
        
        let yellowLayer = CALayer()
        yellowLayer.backgroundColor = UIColor.yellow.cgColor
        yellowLayer.frame = CGRect(x: -50, y: -50, width: 100, height: 100)
        whiteLayer.addSublayer(yellowLayer)

效果如下:

增加masksToBounds属性为true:

whiteLayer.masksToBounds = true

效果如下:

图层边框

CALayer的两个常用属性borderWidth和borderColor,两个属性共同决定了图层边框的样式。边框沿着图层的bounds往内绘制,同时也包含图层的圆角。

borderWidth属性定义了边框的宽度,是浮点数。

borderColor属性定义了边框的颜色默认是黑色,类型为CGColorRef。

我们使用上面的代码为图层添加边框 - 未设置masksToBounds:

        let whiteLayer = CALayer()
        whiteLayer.backgroundColor = UIColor.white.cgColor
        whiteLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        whiteLayer.position = self.view.center
        whiteLayer.cornerRadius = 20.0
        whiteLayer.borderWidth = 2.0
        whiteLayer.borderColor = UIColor.blue.cgColor
        self.view.layer.addSublayer(whiteLayer)
        
        let yellowLayer = CALayer()
        yellowLayer.backgroundColor = UIColor.yellow.cgColor
        yellowLayer.frame = CGRect(x: -50, y: -50, width: 100, height: 100)
        whiteLayer.addSublayer(yellowLayer)

效果如下:

我们发现当设置边框时并不会把寄宿图或者是子图层的形状计算出来,而是沿着图层的边界进行绘制的。

图层阴影

iOS中阴影也是一个十分常见的特性,关于图层阴影的设置涉及到多个属性共同作用。

shadowOpacity:修改这个属性为一个大于0的值,阴影就可以显示在任意图层之下。它是一个介于0和1之间的浮点数。

shadowColor:控制阴影的颜色,它的类型也是CGColorRef,默认为黑色。

shadowOffset:控制阴影的方向和距离,它是一个CGSize值,宽度控制这个阴影的横向位移,高度控制阴影的纵向位移。默认值为{0,-3}向上偏移3。

shadowRadius:控制阴影的模糊程度,当设置为0的时候阴影就和图层一样有一个非常确定的边界线,当值越大边界线看上去就会越模糊和自然。

我们来创建一个橙色的图层并为它添加阴影效果,代码如下:

        self.view.backgroundColor = .white
        
        let originLayer = CALayer()
        originLayer.backgroundColor = UIColor.orange.cgColor
        originLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        originLayer.position = self.view.center
        self.view.layer.addSublayer(originLayer)
        originLayer.shadowOpacity = 0.7
        originLayer.shadowOffset = CGSize(width: 0, height: 3)
        originLayer.shadowRadius = 3
        originLayer.shadowColor = UIColor.black.cgColor

效果如下:

shadowPath:当我们给图层设置阴影属性的时候发现还有一个属性我们没有介绍到shadowPath。

这就意味着阴影的形状我们可以随意绘制,shadowPath是一个CGPathRef类型(一个指向CGPath的指针),CGPath是一个Core Graphics对象,用来指定任意的一个矢量图形。

来修改一下上面的代码为图层添加一个圆形的阴影,代码如下:

        let originLayer = CALayer()
        originLayer.backgroundColor = UIColor.orange.cgColor
        originLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        originLayer.position = self.view.center
        self.view.layer.addSublayer(originLayer)
        originLayer.shadowOpacity = 0.7
        originLayer.shadowOffset = CGSize(width: 0, height: 3)
        originLayer.shadowRadius = 3
        originLayer.shadowColor = UIColor.black.cgColor
        let circlePath = CGPath(roundedRect: CGRect(x: -25, y: -25, width: 250, height: 250), cornerWidth: 250, cornerHeight: 250, transform: nil)
        originLayer.shadowPath = circlePath

效果如下:

图层的阴影另外还有两个特殊的地方,它和图层的边框不同,阴影继承自图层内容的外形,而不是图层的边界和角半径。为了计算出阴影的形状,Core Animation会将寄宿图考虑在内,包括子视图。

下面我们来加载一个图像,代码如下:

        let originLayer = CALayer()
        originLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        originLayer.position = self.view.center
        self.view.layer.addSublayer(originLayer)
        originLayer.shadowOpacity = 0.7
        originLayer.shadowOffset = CGSize(width: 0, height: 3)
        originLayer.shadowRadius = 3
        originLayer.shadowColor = UIColor.black.cgColor
        originLayer.contents = UIImage(named: "icon_dynamic_like_selected")?.cgImage
        originLayer.contentsScale = UIScreen.main.scale

效果如下,Core Animation为我们创建了一个心形的阴影因为图层的内容为心形:

图层阴影的另外一个特殊的地方在于当我们设置masksToBounds的属性为true之后,超出图层部分的阴影会被裁剪掉。

这样给圆角矩形设置阴影的时候就需要花点小心思,比如使用两个相同的图层其中一个设置阴影。

图层蒙版

还有的时候我们希望展示的内容不是在一个矩形也不是圆角矩形,比如说你想显示一个星星,或者显示一个镂空的文字。这个时候我们可以使用图层蒙版来是现实。

CALayer有一个mask属性,这个属性本身就是CALayer类型,它类似一个子图层,它相对父图层进行布局,但是它却不是一个普通的子图层,mask图层定义了父图层的部分可见区域。

mask图层的color属性是无关紧要的,真正重要的是图层的轮廓。mask属性就像一个模型切割机,mask图层实心的部分也就是不透明的部分会被保留下来。

如果mask图层比父图层小,那么只有在mask图层里面的内容才是它关心的,除此之外的一切都会被隐藏起来。

下面我们来创建一个例子:

​​​​​​​

当我们设置为子图层的时候显示效果如下:

当我们设置为mask的时候代码如下:

        // 背景
        let bgLayer = CALayer()
        bgLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        bgLayer.position = self.view.center
        bgLayer.contents = UIImage(named: "random_dynamic_pic_0")?.cgImage
        bgLayer.contentsScale = UIScreen.main.scale
        self.view.layer.addSublayer(bgLayer)
        // 蒙版
        let maskLayer = CALayer()
        maskLayer.frame = CGRect(x: 70, y: 70, width: 50, height: 50)
        maskLayer.contents = UIImage(named: "icon_dynamic_like_selected")?.cgImage
        maskLayer.contentsScale = UIScreen.main.scale
        bgLayer.mask = maskLayer

效果如下:

图层的拉伸过滤方式

最后我们再来谈一下图层的minificationFilter和magnificationFilter属性,这两个属性我们不常用,他们定义了图片在被拉伸或者被压缩时采用的拉伸过滤方式。

CALayer提供了三种拉伸过滤方式:

  • CALayerContentsFilter.linear
  • CALayerContentsFilter.nearest
  • CALayerContentsFilter.trilinear

通常来讲这两个属性的默认值都是.linear,既采用双线性滤波算法过滤器进行压缩和拉伸,大多数情况下都表现良好,双线性滤波算法通过对个像素取样来生成最终的值,会得到一个还不错的拉伸效果,但是当放大倍数比较大的时候就模糊不清了。

.trailinear和.linear非常相似,大部分情况下二者都看不出来有啥区别。相对双线性滤波算法,三线性滤波算法存储了多个大小情况下的图片,并三维取样,同时结合大图和小图的存储进而得到最后的结果。

.nearest是一种比较武断的方案,这个算法就是取样最近的单像素点,而不管其它的颜色,这样做非常快。但是最明显的效果就是会使得压缩图片更糟,放大之后也会有明显的马赛克,但是它也有适用的地方,比如对于没有斜线的小图来说最近过滤算法就要好很多。

下面举两个例子,一个带斜线的小图,图片的原始大小是50*30,我们分别使用三种算法来进行放大3倍。

代码如下:

       // 原始比例
        let orginLayer = CALayer()
        orginLayer.frame = CGRect(x: 70, y: 100, width: 50, height: 30)
        orginLayer.contents = UIImage(named: "Property 1=ktv")?.cgImage
        orginLayer.contentsScale = UIScreen.main.scale
        self.view.layer.addSublayer(orginLayer)
        
        // 放大3倍 - 双线性滤波算法
        let magLayer = CALayer()
        magLayer.frame = CGRect(x: 70, y: 200, width: 50 * 3, height: 30 * 3)
        magLayer.contents = UIImage(named: "Property 1=ktv")?.cgImage
        magLayer.contentsScale = UIScreen.main.scale
        magLayer.magnificationFilter = .linear
        self.view.layer.addSublayer(magLayer)
        // 放大3倍 - 三线性滤波算法
        let magLayer1 = CALayer()
        magLayer1.frame = CGRect(x: 70, y: 300, width: 50 * 3, height: 30 * 3)
        magLayer1.contents = UIImage(named: "Property 1=ktv")?.cgImage
        magLayer1.contentsScale = UIScreen.main.scale
        magLayer1.magnificationFilter = .trilinear
        self.view.layer.addSublayer(magLayer1)
        // 放大3倍 - 最近邻滤波算法
        let magLayer2 = CALayer()
        magLayer2.frame = CGRect(x: 70, y: 400, width: 50 * 3, height: 30 * 3)
        magLayer2.contents = UIImage(named: "Property 1=ktv")?.cgImage
        magLayer2.contentsScale = UIScreen.main.scale
        magLayer2.magnificationFilter = .nearest
        self.view.layer.addSublayer(magLayer2)

效果如下:

我们来更换一张不带斜边的图片,效果如下:

总的来说呢,相对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特性以呈现更好的结果。

但是对于大多数图图尤其是有很多斜线或者曲线的图片来说,双线性和三线形滤波算法的结果更好些,而最近过滤算法会极差。

换句话说,线性过滤保留了形状,而最近过滤保留了像素差异。

总结

本篇博客介绍了一些使用代码可以实现的图层的视觉特效,比如阴影,蒙版,圆角。又介绍了一些拉伸过滤的方案。

下篇博客我们开始研究图层的变化。

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

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

相关文章

喜讯!安全狗荣获“2023年网络安全技术支撑优秀单位”称号

6月6日,由中共厦门市委网络安全和信息化委员会办公室(以下简称“厦门市委网信办”)主办的2023年网络安全技术支撑优秀单位颁奖仪式在厦门成功举行。 作为国内云原生安全领导厂商,安全狗受邀出席此次活动。 会上,安全狗…

DEBOPIE框架:打造最好的ChatGPT交易机器人

本文介绍了如何利用 DEBOPIE 框架并基于 ChatGPT 创建高效交易机器人,并强调了在使用 AI 辅助交易时需要注意的限制以及操作步骤。原文: Build the Best ChatGPT Trading Bots with my “DEBOPIE” Framework 如今有大量文章介绍如何通过 ChatGPT 帮助决定如何以及在…

做工作室项目重要还是运营重要

做工作室项目重要还是运营重要,先说答案,项目好是基础,然后才能谈运营! 90%的工作室活不过一年,这句话是有数据支撑的,因为就工商注册的公司而言,一年内倒闭的就是这么个数据,所以工…

在AvaotaA1全志T527开发板上烧录AvaotaOS固件

烧写到 TF 卡上 材料准备 首先需要准备的材料有: SD-Card Formatter:balenaEtcherAvaota Pi - A1开发板 x1TF-Card ( 不小于4Gb ) x112V-DC电源适配器 x1TF读卡器 x1USBTTL Splitter x1(可选)HDMI 采集卡 x1 (可选)…

input调用手机摄像头实现拍照功能vue

项目需要一个拍照功能&#xff0c;实现功能如下图所示:若使用浏览器则可以直接上传图片&#xff0c;若使用手机则调用手机摄像头拍照。 1.代码结构 <!--input标签--> <input ref"photoRef"type"file"accept"image/*"capture"envir…

DM表级触发器

可以理解为行变动级 触发体中写逻辑 这是表修改时调用存储过程 感谢大哥分享: https://blog.csdn.net/WuLex/article/details/83181449 感谢大哥分享: https://blog.csdn.net/ChennyWJS/article/details/131913198

前置章节-熟悉Python、Numpy、SciPy和matplotlib

目录 一、编程环境-使用jupyter notebook 1.下载homebrew包管理工具 2.安装Python环境 3.安装jupyter 4.下载Anaconda使用conda 5.使用conda设置虚拟环境 二、学习Python基础 1.快排的Python实现 (1)列表推导-一种创建列表的简洁方式 (2)列表相加 2.基本数据类型及运…

数学建模比赛介绍与写作建议

0 小序 本文的写作起因是导师要求我给打算参加相关竞赛的师弟们做一次讲座和汇报。我梳理了一个ppt提纲&#xff0c;并经过整理&#xff0c;因此有了这篇文章。 我打算从数学建模论文写作格式和写作技巧入手&#xff0c;接着介绍数学建模常用的数学模型&#xff0c;最后提出一…

MSPM0G3507——串口

配置&#xff1a; 主函数: #include "ti_msp_dl_config.h"volatile uint8_t gEchoData 0; int main(void) {SYSCFG_DL_init();NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); //先清除中断&#xff0c;防止直接进中断NVIC_EnableIRQ(…

【前端】从零开始学习编写HTML

目录 一、什么是前端 二、什么是HTML 三、HTML文件的基本结构 四、HTML常见标签 4.1 注释标签 4.2 标题标签 4.3 段落标签 4.4 换行标签 4.5 格式化标签 4.6 图片标签 4.7 超链接标签 4.8 表格标签 4.9 列表标签 4.10 表单标签 &#xff08;1&#xff09;form标…

ThreeJS-3D教学十二:ShaderMaterial

一、首先 Shader 是做什么的 Shader 可以自定义每个顶点、每个片元/像素如何显示&#xff0c;而控制顶点和片元显示是通过设置 vertexShader 顶点着色器和 fragmentShader 片元着色器&#xff0c;这两个着色器用在 ShaderMaterial 和 RawShaderMaterial 材质上。 我们先看一个例…

SpringMVC系列八: 手动实现SpringMVC底层机制-第二阶段

实现任务阶段三 &#x1f34d;从web.xml动态获取zzwspringmvc.xml 说明: 前面我们加载zzwspringmvc.xml是硬编码, 现在做活. 从web.xml动态获取 示意图[分析说明] 1.ZzwDispatcherServlet在创建并初始化ZzwWebApplicationContext时, 动态地从web.xml中获取到spring配置文…

Linux中定位JVM问题常用命令

查询Java进程ID #ps axu | grep java #ps elf | grep java查看机器负载及CPU信息 #top -p 1(进程ID) #top (查看所有进程)获取CPU飙升线程堆栈 1. top -c 找到CPU飙升进程ID&#xff1b; 2. top -Hbp 9702(替换成进程ID) 找到CPU飙升线程ID&#xff1b; 3. $ printf &quo…

Redis 必备的原理知识要点

1、为什么使用缓存&#xff1f; 1、数据库太慢-无法使用 2、高性能 3、高并发 4、热点高频数据 2、redis合适的场景&#xff1f; 1、数据类型 5种&#xff1b; 2、Bitmap&#xff1b; 3、HyperLogLog&#xff1b; 结合自身项目讲解redis的使用&#xff1a; 1、token&a…

考研数学|考到110到底有多难?

考研数学一要考到110分&#xff0c;确实不容易。数学一的难度在于它涉及的知识点多&#xff0c;包括高等数学、线性代数和概率论。这些内容不仅要求你理解深刻&#xff0c;还要能熟练运用。特别是高等数学&#xff0c;它在考试中的分值占比最高&#xff0c;也是最难的部分。 数…

SAMformer:通过锐度感知最小化和通道注意力解锁变换器在时间序列预测中的潜力

目录 摘要1. 引言当前方法的局限性变换器的可训练性我们贡献的总结 2. 提出的方法符号说明2.1 问题设置2.2 激励示例命题2.1&#xff08;最优解的存在性&#xff09; 2.3 变换器的损失景观现有的解决方案 2.4. SAMformer&#xff1a;集成所有方法 3. 实验3.1 主要收获 摘要 基…

目标检测算法的研究现状

一、引言 目标检测是计算机视觉领域中的一项重要任务&#xff0c;旨在从图像或视频中识别并定位出感兴趣的目标物体。随着深度学习技术的快速发展&#xff0c;目标检测算法取得了显著的进步&#xff0c;并在自动驾驶、智能安防、人脸识别等领域得到了广泛应用。本文将对目标检…

2024上海初中生古诗文大会倒计时4个月:单选题真题和独家解析

现在距离2024年初中生古诗文大会初选还有4个多月时间&#xff08;11月3日正式开赛&#xff09;&#xff0c;我们继续来看10道选择题真题和详细解析&#xff0c;以下题目截取自我独家制作的在线真题集&#xff0c;都是来自于历届真题&#xff0c;去重、合并后&#xff0c;每道题…

电商价格监测:品牌控价维权的关键利器

品牌在进行控价时&#xff0c;所面对的是线上成千上万条的商品链接&#xff0c;如果仅依靠人工&#xff0c;根本无法做到准确且全面地完成电商价格监测工作。因此&#xff0c;一套准确率高的电商价格监测系统对于品牌的控价维权而言&#xff0c;其重要性不言而喻。 在形形色色的…

UE4_材质_材质节点_视差偏移BumpOffset

一、定义 凹凸贴图偏移&#xff08;BumpOffset&#xff09; 是虚幻引擎4术语&#xff0c;就是通常所谓的"视差贴图"。BumpOffset表达式可以使材质产生深度错觉&#xff0c;而不需要额外的几何体。BumpOffset材质使用灰阶_高度贴图_来提供深度信息。高度贴图中的值越…