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

引言

在前几篇博客中我们讨论了图层的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)

效果如下:

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

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

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

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

总结

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习环境搭建

前言 个人笔记,记录框架和小问题,没有太详细记载。。 1、Anaconda安装 下载地址: Free Download | Anaconda (慢) ​ 国内镜像:https://link.csdn.net/?targethttp%3A%2F%2Fitcxy.xyz%2F241.html 下载…

五国如何实现关键基础设施保护方法的现代化

本叙述介绍了关键基础设施面临的不断演变的风险,并讨论了关键五国(澳大利亚、加拿大、新西兰、英国和美国)如何实现关键基础设施保护方法的现代化。它还确定了加强国内关键基础设施安全性和弹性的共同方法,同时认识到鉴于关键基础设施的相互关联性,国际社会需要采取合作和…

【H.264】五分钟入门H.264协议

<> 博客简介&#xff1a;Linux、rtos系统&#xff0c;arm、stm32等芯片&#xff0c;嵌入式高级工程师、面试官、架构师&#xff0c;日常技术干货、个人总结、职场经验分享   <> 公众号&#xff1a;嵌入式技术部落   <> 系列专栏&#xff1a;C/C、Linux、rt…

以现在的社会形势走向,选什么专业好?

随着高考结束&#xff0c;选专业的话题又开始变得越来越热门。因为很多学生都想知道自己更适合什么样的专业&#xff0c;如何结合未来的社会形势来选择更好的专业&#xff0c;这的确是一个很考验能力的问题&#xff0c;因为有太多人曾经为了选择专业而纠结过。 高考志愿填报选…

基于多源数据的密码攻防领域知识图谱构建

源自&#xff1a; 信息安全与通信保密杂志社 作者&#xff1a;曹增辉 , 郭渊博 , 黄慧敏 摘 要 提高网络空间安全的密码攻防能力&#xff0c;需要形成可表示、可共享、可分析的领域知识模式和知识库。利用自顶向下的构建方法&#xff0c;并通过本体构建方法梳理密码攻防领域…

Nginx 配置文件

Nginx的配置文件的组成部分&#xff1a; 主配置文件&#xff1a;nginx.conf子配置文件&#xff1a;include conf.d/*.conf 全局配置 nginx 有多种模块 核心模块&#xff1a;是 Nginx 服务器正常运行必不可少的模块&#xff0c;提供错误日志记录 、配置文件解析 、事件驱动机…

Android Studio 2023版本切换DNK版本

选择自己需要的版本下载 根目录下的配置路劲注意切换 build.gradle文件下的ndkVersion也要配好对应版本

现代信息检索笔记(二)——布尔检索

目录 信息检索概述 IR vs数据库: 结构化vs 非结构化数据 结构化数据 非结构化数据 半结构化数据 传统信息检索VS现代信息检索 布尔检索 倒排索引 一个例子 建立词项&#xff08;可以是字、词、短语、一句话&#xff09;-文档的关联矩阵。 关联向量 检索效果的评价 …

使用Visual Studio Code记笔记

因为学习需要&#xff0c;记笔记是很有必要的&#xff0c;平常发CSDN&#xff08;都让CSDN是很棒的哈&#xff09;&#xff0c;后来使用VS Code的时候发现了很多插件&#xff0c;觉得做笔记还是相对不错的&#xff0c;主要用到的还是Markdown 主要设计的插件包括&#xff1a; …

第3章:数据结构

树 对稀疏矩阵的压缩方法有三种&#xff1a; 1、三元组顺序表 2、行逻辑连接的顺序表 3、十字链表 同义词才会占用同个位置&#xff0c;从而需要进行多次比较。这些关键字的第一个可以不是e的同义词&#xff0c;可以是排在e之前的关键字正好占了那个位置。 Dijkstra算法主要特点…

MySQL 高级SQL高级语句(二)

一.CREATE VIEW 视图 可以被当作是虚拟表或存储查询。 视图跟表格的不同是&#xff0c;表格中有实际储存数据记录&#xff0c;而视图是建立在表格之上的一个架构&#xff0c;它本身并不实际储存数据记录。 临时表在用户退出或同数据库的连接断开后就自动消失了&#xff0c;而…

javassmmysql 宣和酒店点餐系统37378-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 1 绪论 1.1研究背景 1.2目的 1.3ssm框架介绍 1.3论文结构与章节安排 2 宣和酒店点餐系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章…

Pascal 函数入门示例,及其汇编语言分析

1&#xff0c; Pascal 函数的定义格式 pascal 函数的定义语法格式: FUNCTION 函数名(形式参数表):函数类型; VAR 函数的变量说明; BEGIN 函数体; END; 2&#xff0c;Pascal 函数定义调用示例 order_self.pas 代码&#xff1a; PROGRAM example01;va…

黑龙江等保测评科普

黑龙江的等保测评&#xff0c;即信息安全等级保护测评&#xff0c;是中国网络安全法框架下的一项重要制度&#xff0c;旨在提升信息系统安全水平&#xff0c;保护关键信息基础设施免受威胁。下面是对黑龙江等保测评流程和要求的科普&#xff1a; 1. 等保测评概念 定义&#xff…

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…

操作系统精选题(三)(简答题、概念题)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;操作系统 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 简答题 一、对 CPU、内存、外设并…

SpringCloud和Dubbo有什么区别

SpringCloud与Dubbo的区别 两者都是现在主流的微服务框架&#xff0c;但却存在不少差异&#xff1a; 初始定位不同&#xff1a; SpringCloud定位为微服务架构下的一站式解决方案&#xff1b;Dubbo 是 SOA 时代的产物&#xff0c;它的关注点主要在于服务的调用和治理 生态环境…

【linux】 给命令添加别名

【linux】 给命令添加别名 文章目录 【linux】 给命令添加别名1.修改2.效果 1.修改 2.效果

【AI大模型】跌倒监控与健康:技术实践及如何改变未来

文章目录 1. **背景与意义**2. **关键技术与方法**2.1 传感器数据融合2.2 深度学习模型2.3 行为模式识别2.4 预测与预防 3. **应用场景**3.1 老年人跌倒预警3.2 康复患者监测3.3 高风险职业防护 4. **实践案例**案例1&#xff1a;某老年社区的跌倒预警系统案例2&#xff1a;康复…

R语言数据分析案例39-合肥市AQI聚类和多元线性回归

一、研究背景 随着全球工业化和城市化的迅速发展&#xff0c;空气污染问题日益凸显&#xff0c;已成为影响人类健康和环境质量的重大挑战。空气污染不仅会引发呼吸系统、心血管系统等多种疾病&#xff0c;还会对生态系统造成不可逆转的损害。因此&#xff0c;空气质量的监测和…