九.核心动画 - 显式动画

引言

本篇博客紧接着上一篇的隐式动画开始介绍显式动画。隐式动画是创建动态页面的一种简单的直接的方式,也是UIKit的动画机制基础。但是它并不能涵盖所有的动画类型。

显式动画

接下来我们就来研究另外一种动画显式动画,它能够对一些属性做指定的动画,或者非线性动画。

显式动画 - 属性动画

给一个图层的属性添加动画时,我们需要借助CAAnimationDelegate代理,这个代理我们可以在CAAnimation的文件中找到,它有两个方法:

动画已经开始

    optional func animationDidStart(_ anim: CAAnimation)

动画已经结束

optional func animationDidStop(_ anim: CAAnimation, finished flag: Bool)

下面的例子中我们使用属性动画来修改图层的颜色,并在动画结束之后来设置图层最终颜色。

这里面有一个需要注意的地方,如果我们给单独的图层添加动画,需要在一个新的事物中来进行,并且禁用图层的默认行为,否则动画会发生两次,一次是我们设置的显式动画,一个是图层默认的隐式动画。

代码如下:

class ViewController: UIViewController, CAAnimationDelegate{let colorLayer = CALayer()override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view.colorLayer.frame = CGRect(x: 50, y: 100, width: 100, height: 100)colorLayer.backgroundColor = UIColor.red.cgColorself.view.layer.addSublayer(colorLayer)}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let colors = [UIColor.red.cgColor, UIColor.green.cgColor, UIColor.blue.cgColor]let animation = CABasicAnimation()animation.keyPath = "backgroundColor"animation.toValue = colors.randomElement()animation.duration = 1.0animation.delegate = selfcolorLayer.add(animation, forKey: nil)}func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {if let animation = anim as? CABasicAnimation {CATransaction.begin()CATransaction.setDisableActions(true)let cgColor = animation.toValuecolorLayer.backgroundColor =  (cgColor as! CGColor)CATransaction.commit()}}}

动画的结束事件,是使用代理的方法来实现的,这样会有一个问题。就是假如一个控制器中有多个图层进行动画,那么所有的动画都会使用这一个回调方法,这样的话我们就需要判断是哪个图层动画的回调。

在添加动画时我们发现open func add(_ anim: CAAnimation, forKey key: String?)有一个key属性,目前设置的为nil。事实上它就是东湖的唯一标识符,我们给它设置一个非空的唯一字符串,在回调的时候就可以对所有图层进行循环,调用-animationForKey:来比对结果。

我们来修改一下代码:

        colorLayer.add(animation, forKey: "colorChange")
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {if colorLayer.animation(forKey: "colorChange") == anim {if let animation = anim as? CABasicAnimation {CATransaction.begin()CATransaction.setDisableActions(true)let cgColor = animation.toValuecolorLayer.backgroundColor =  (cgColor as! CGColor)CATransaction.commit()}}}

但是当有很多很多图层有很多很多动画的话,这个方法就显得不太优雅了。

不过我们还有更简单的版本。CAAnimation也显示了KVC协议,所以我们可以使用open func setValue(_ value: Any?, forKey key: String)和open func value(forKey key: String) -> Any?两个方法来存取属性。但是CAAnimation还有一个不同的地方,它更新时一个NSDictionary,我们可以随意设置键值对。

这就意味着我们可以对动画打任何类型的标签,下面我们就来写个例子感受一下这个特性:

class ViewController: UIViewController, CAAnimationDelegate{let firstView = UIView()let secondView = UIView()let thirdView = UIView()override func viewDidLoad() {super.viewDidLoad()self.view.addSubview(firstView)firstView.backgroundColor = .redfirstView.frame = CGRect(x: 40.0, y: self.view.bounds.size.height - 300.0, width: 40.0, height: 10.0)self.view.addSubview(secondView)secondView.backgroundColor = .greensecondView.frame = CGRect(x: 80.0, y: self.view.bounds.size.height - 300.0, width: 40.0, height: 10.0)self.view.addSubview(thirdView)thirdView.backgroundColor = .bluethirdView.frame = CGRect(x: 120.0, y: self.view.bounds.size.height - 300.0, width: 40.0, height: 10.0)}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {addAnimation(view: firstView, height: 100.0)addAnimation(view: secondView, height: 200.0)addAnimation(view: thirdView, height: 300.0)}func addAnimation(view:UIView,height:CGFloat) {let animation = CABasicAnimation()animation.keyPath = "bounds.size.height"animation.toValue = heightanimation.duration = 1.0animation.delegate = selfanimation.setValue(view, forKey: "view")view.layer.add(animation, forKey: nil)}func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {guard let anim = anim as? CABasicAnimation else {return}if let view = anim.value(forKey: "view") as? UIView {let height = anim.toValue as? CGFloatview.layer.bounds.size.height = height!}}}

点击屏幕后发现,每个动画的结果都对应到了自己的图层,效果如下:

可以做动画的属性和虚拟属性非常的多,我们就来列举一些常见的几何属性吧

  • tranform.rotation.x        按x轴旋转的弧度
  • tranform.rotation.y        按y轴旋转的弧度
  • tranform.rotation.z        按z轴旋转的弧度
  • tranform.rotation        按z轴旋转的弧度,和tranform.rotation.z效果一样
  • tranform.scale.x        在x轴按比例放大缩小
  • tranform.scale.y        在y轴按比例放大缩小
  • tranform.scale.z        在z轴按比例放大缩小
  • tranform.scale        整体按比例放大缩小
  • transform.translation.x        沿x轴平移
  • transform.translation.y        沿y轴平移
  • transform.translation.z        沿z轴平移
  • transform.translation        x,y坐标均发生改变
  • transform        CATransform3D 4xbounds4矩阵
  • bounds        layer大小
  • position        layer位置
  • anchorPoint        锚点位置
  • cornerRadius        圆角大小
  • ZPosition        Z轴位置

显式动画 - 关键帧动画

CAKeyframeAnimation是另一种UIKit没有暴露出来的且功能十分强大的类。和CABasicAnimation一样它也是继承自CAPropertyAnimation,并且它也作用于单一的一个属性,不同的是它不是只设置一个起始值和一个结束值。而是可以设置一连串随意的值来做动画。

关键帧动画起源于传动动画。它的主要思想是指主导的动画在显著改变发生时重绘当前帧,也就是关键帧。而关键帧与关键帧之间的绘制则由Core Animation通过推算来完成。

我们来使用一个例子,通过关键帧动画来修改图层的颜色,代码如下:

class ViewController: UIViewController, CAAnimationDelegate{let colorLayer = CALayer()override func viewDidLoad() {super.viewDidLoad()colorLayer.frame = CGRect(x: 50, y: 100, width: 100, height: 100)colorLayer.backgroundColor = UIColor.red.cgColorself.view.layer.addSublayer(colorLayer)}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let animation = CAKeyframeAnimation()animation.keyPath = "backgroundColor"animation.duration = 2.0animation.values = [UIColor.red.cgColor, UIColor.green.cgColor, UIColor.blue.cgColor,UIColor.yellow.cgColor]animation.keyTimes = [0.0, 0.25, 0.5, 0.75, 1.0]colorLayer.add(animation, forKey: nil)}

效果如下:

CAKeyframeAnimation还有另外一种方式来指定动画,就是使用CGPath。path属性可以用一种更直观的方式来描述动画,我们这次采用UIKit提供的UIBezierPath来创建path,并且为了更直观我们使用CAShapeLayer将path渲染出来。然后我们在设置CAKeyframeAnimation来创建我们的动画。

代码如下:

        let bezierPath = UIBezierPath()bezierPath.move(to: CGPoint(x: 50, y: 150))bezierPath.addCurve(to: CGPoint(x: 300, y: 150), controlPoint1: CGPoint(x: 150, y: 50), controlPoint2: CGPoint(x: 200, y: 250))let shapeLayer = CAShapeLayer()shapeLayer.path = bezierPath.cgPathshapeLayer.fillColor = UIColor.clear.cgColorshapeLayer.strokeColor = UIColor.red.cgColorshapeLayer.lineWidth = 3.0self.view.layer.addSublayer(shapeLayer)let layer = CALayer()layer.frame = CGRect(x: 50 - 40, y: 150 - 40, width: 40, height: 40)layer.contents = UIImage(named: "a-meiguihuahuameigui")?.cgImageself.view.layer.addSublayer(layer)let animation = CAKeyframeAnimation()animation.keyPath = "position"animation.path = bezierPath.cgPathanimation.duration = 4.0layer.add(animation, forKey: nil)

效果如下:

还可以体验一下animation.rotationMode = .rotateAuto这个属性。

        let animation = CAKeyframeAnimation()animation.keyPath = "position"animation.path = bezierPath.cgPathanimation.duration = 4.0animation.rotationMode = .rotateAutolayer.add(animation, forKey: nil)

你会发现,花会沿着曲线运动时会发生旋转,使自己总垂直于曲线。

结语

本篇博客介绍了两个最常用的显式动画,属性动画和关键帧动画。大家在实际开发过程中应该经常会使用到。接下来的博客我们会继续讨论显式动画,进行动画的组合,过渡动画,以及取消动画。

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

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

相关文章

常用知识碎片 Vue3 ref和reactive (内含其他常用知识)

目录 ref和reactive ref reactive 总结&#xff1a; setup语法糖 语法糖是啥&#xff1f; Vue3 setup语法糖 Vue3 不使用setup语法糖示例&#xff1a; Vue3 使用setup语法糖示例&#xff1a; ref和eative主要区别 ref和reactive 在 Vue 3 中&#xff0c;ref 和 reac…

品牌渠道管控力度的平衡艺术

渠道管控力度要如何把握呢&#xff1f;是不是管控越严格就一定越好&#xff1f;例如&#xff0c;发现一次低价就处以高额罚款&#xff0c;发现一次窜货也重罚&#xff0c;其实处罚是对低价管控较为直接的一种方式&#xff0c;但并非处罚越重就一定能取得良好的管控效果。 比如品…

Java 中的 switch 语句:类型支持与限制

Java 中的 switch 语句&#xff1a;类型支持与限制 1、switch 语句支持的数据类型2、switch 语句不支持的数据类型3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在 Java 中&#xff0c;switch 语句是一种用于多分支选择的控制结构…

如何使用FreeFileSync:一款免费且专业的数据备份与文件同步软件

数据的重要性不言而喻&#xff0c;因此&#xff0c;定期做数据备份已经是每一个人的基本工作习惯了。 FreeFileSync 是一款强大专业且免费开源的 文件夹对比/同步/备份 软件工具。FreeFileSync通过比较其内容&#xff0c;日期或文件大小上的一个或多个文件夹&#xff0c;然后根…

统信UOS桌面操作系统上删除系统升级后GRUB中的回滚条目与备份

原文链接&#xff1a;统信UOS删除升级后GRUB中的回滚条目与备份 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在统信UOS桌面操作系统上删除系统升级后GRUB中的回滚条目与备份的文章。在进行系统升级后&#xff0c;GRUB引导菜单中可能会出现多个回滚条目和备份…

nginx正向代理、反向代理、负载均衡

nginx.conf nginx首要处理静态页面 反向代理 动态请求 全局模块 work processes 1; 设置成服务器内核数的两倍&#xff08;一般不不超过8个超过8个反而会降低性能一般4个 1-2个也可以&#xff09; netstat -antp | grep 80 查端口号 *1、events块&#xff1a;* 配置影响ngi…

aws sap认证考试如何轻松通过

如何高效备考AWS SAP (Solutions Architect Professional) 认证? AWS SAP认证是AWS认证体系中难度最高的认证之一,要通过这个考试确实需要下一番功夫。但通过合理规划和有效准备,你可以提高通过的几率。以下是一些建议: 评估起点 首先诚实地评估自己的AWS知识水平和实践经验。…

气膜滑冰馆:滑冰爱好者的最佳选择—轻空间

滑冰运动在全球范围内越来越受欢迎&#xff0c;然而&#xff0c;传统滑冰馆在建设和运营过程中往往面临高能耗和环境控制难题。幸运的是&#xff0c;采用气膜结构作为建筑外壳的气膜滑冰馆&#xff0c;正在为滑冰爱好者提供一种全新的、节能的解决方案。 1. 气膜结构&#xff1…

MES 功能模块

MES系统&#xff08;Manufacturing Execution System&#xff0c;生产执行系统&#xff09;是制造业企业的关键管理系统之一&#xff0c;它通过集成生产计划、工艺流程、物料管理和生产过程数据等&#xff0c;实现了对生产和制造过程的全面管理和监控。MES系统的功能模块主要包…

【线性表,线性表中的顺序表和链表】

目录 1、线性表的定义和基本操作1.1、线性表的定义1.2、线性表的基本操作 2、顺序表和链表的比较2.1、顺序表2.1.1、顺序表的定义和特点2.1.2、顺序表的实现&#xff08;1&#xff09;顺序表的静态分配&#xff1a;&#xff08;2&#xff09;顺序表的动态分配 2.1.3、顺序表的基…

昇思25天学习打卡营第17天|基于MobileNetv2的垃圾分类

今天学习的内容是利用视觉图像技术&#xff0c;来实现垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 本章节主要包括8部分内容&#xff1a; 1、实验目的 1、了解熟悉垃圾分类应用…

气膜滑雪馆如何实现恒温—轻空间

随着滑雪运动的普及和爱好者数量的增加&#xff0c;滑雪馆的建设需求也不断提升。然而&#xff0c;如何在滑雪馆内保持恒温&#xff0c;提供一个稳定舒适的滑雪环境&#xff0c;成为了建设过程中需要解决的关键问题。气膜滑雪馆凭借其独特的结构和技术优势&#xff0c;成功地实…

MQTT是什么,物联网

写文思路&#xff1a; 以下从几个方面介绍MQTT&#xff0c;包括&#xff1a;MQTT是什么&#xff0c;MQTT和webSocket的结合&#xff0c;以及使用场景&#xff0c; 一、MQTT是什么 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的发布/订阅消息…

如何分辨AI生成的内容?AI生成内容检测工具对比实验

检测人工智能生成的文本对各个领域的组织都提出了挑战&#xff0c;包括学术界和新闻界等。生成式AI与大语言模型根据短描述来进行内容生成的能力&#xff0c;产生了一个问题&#xff1a;这篇文章/内容/作业/图像到底是由人类创作的&#xff0c;还是AI创作的&#xff1f;虽然 LL…

LabVIEW实现LED显示屏视觉检测

为了满足LED显示屏在生产过程中的严格质量检测需求&#xff0c;引入自动化检测系统是十分必要的。传统人工检测方式存在检测强度高、效率低、准确性差等问题&#xff0c;自动化检测系统则能显著提高检测效率和准确性。视觉检测系统的构建主要包含硬件和软件两个部分。 视觉系统…

昇思25天学习打卡营第23天 | Pix2Pix实现图像转换

内容介绍&#xff1a; Pix2Pix是基于条件生成对抗网络&#xff08;cGAN, Condition Generative Adversarial Networks &#xff09;实现的一种深度学习图像转换模型&#xff0c;该模型是由Phillip Isola等作者在2017年CVPR上提出的&#xff0c;可以实现语义/标签到真实图片、灰…

Python酷库之旅-第三方库Pandas(016)

目录 一、用法精讲 39、pandas.DataFrame.to_stata函数 39-1、语法 39-2、参数 39-3、功能 39-4、返回值 39-5、说明 39-6、用法 39-6-1、数据准备 39-6-2、代码示例 39-6-3、结果输出 40、pandas.read_stata函数 40-1、语法 40-2、参数 40-3、功能 40-4、返回…

nssm的下载和使用

nssm&#xff08;Non-Sucking Service Manager&#xff09;是一个用于在Windows系统上管理服务的工具。它允许你将.exe文件和.bat文件转换为Windows服务&#xff0c;并提供了一些功能来管理这些服务。 下载和安装 首先&#xff0c;你需要从nssm官方网站&#xff08;https://n…

【ARM】MDK安装ARM_compiler5无法打开安装程序

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 在客户安装了最新版本的MDK5.37及后续更新版本&#xff0c;但原工程使用ARM_Compiler_5.06进行编译和调试&#xff0c;需安装ARM_Compiler_5.06的编译器版本&#xff0c;但在解压缩的过程中后续无法打开ARM_Compiler…

解释 C 语言中的递归函数

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; &#x1f4d9;C 语言百万年薪修炼课程 通俗易懂&#xff0c;深入浅出&#xff0c;匠心打磨&#xff0c;死磕细节&#xff0c;6年迭代&#xff0c;看过的人都说好。 文章目…