移动端访问不佳,请访问我的个人博客

前段时间在github上看见一个非常nice的动画效果,可惜是安卓的,想着用Swift写一个iOS版的,下下来源代码研究了一下,下面是我写代码的心路历程

先上图和demo的地址

分析动画过程

刚开始看的时候感觉这个动画很炫酷,实现起来应该挺复制的,后来我将gif图逐一分解,浏览了一下安卓的实现过程,大致了解的实现的过程,下面是一些关键的动画步骤:

  1. 第一步是里面图片的缩放动画,使用CALayer配合CAKeyframeAnimation来实现;
  2. 第二步是是里面一个圆环逐渐变大的过程,使用CAShapeLayer配合CAKeyframeAnimation来实现;
  3. 第三步是最外面一层太阳的扩散效果同样也使用CAShapeLayer配合CAKeyframeAnimation来实现;
  4. 最后是闪烁和颜色变化的的效果,使用CABasicAnimationCADisplayLink来实现。

一、缩放动画的实现

这个实现的过程相对而言比较简单,用CALayer做为mask来实现下图心形的图片,然后用CAKeyframeAnimation来实现动画,values的值为[0.4, 1, 0.9, 1],差值器模式为kCAAnimationCubic,下面是实现结果和关键代码:

public func startAnim() {let anim = CAKeyframeAnimation(keyPath: "transform.scale")anim.duration  = animDurationanim.values = [0.4, 1, 0.9, 1]anim.calculationMode = kCAAnimationCubicmaskLayer.add(anim, forKey: "scale")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二、圆环扩散动画的实现

首先圆环我们用CAShapeLayer来绘制一个圆环,然后通过CAKeyframeAnimation来改变圆环的path就可以了,下面是实现结果和关键代码:

public func startAnim() {let anim = CAKeyframeAnimation(keyPath: "path")anim.duration = params.animDuration * 0.1let size = frame.sizelet fromPath = UIBezierPath(arcCenter: CGPoint.init(x: size.width/2, y: size.height/2), radius: 1, startAngle: 0, endAngle: CGFloat(M_PI) * 2.0, clockwise: false).cgPathlet toPath = UIBezierPath(arcCenter: CGPoint.init(x: size.width/2, y: size.height/2), radius: size.width/2 * CGFloat(params.shineDistanceMultiple), startAngle: 0, endAngle: CGFloat(M_PI) * 2.0, clockwise: false).cgPathanim.delegate = selfanim.values = [fromPath, toPath]anim.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)]anim.isRemovedOnCompletion = falseanim.fillMode = kCAFillModeForwardsshapeLayer.add(anim, forKey: "path")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三、太阳的扩散效果实现

首先我们得先算出每个太阳的位置和将要扩散到的位置,然后用CAShapeLayer绘制出太阳,用CAKeyframeAnimation实现扩散的效果,下面是实现后的结果和关键代码 :

public func startAnim() {let radius = frame.size.width/2 * CGFloat(params.shineDistanceMultiple*1.4)var startAngle: CGFloat = 0let angle = CGFloat(M_PI*2/Double(params.shineCount)) + startAngleif params.shineCount%2 != 0 {startAngle = CGFloat(M_PI*2 - (Double(angle)/Double(params.shineCount)))}for i in 0..<params.shineCount {let bigShine = shineLayers[i]let bigAnim = getAngleAnim(shine: bigShine, angle: startAngle + CGFloat(angle)*CGFloat(i), radius: radius)let smallShine = smallShineLayers[i]var radiusSub = frame.size.width*0.15*0.66if params.shineSize != 0 {radiusSub = params.shineSize*0.66}let smallAnim = getAngleAnim(shine: smallShine, angle: startAngle + CGFloat(angle)*CGFloat(i) - CGFloat(params.smallShineOffsetAngle)*CGFloat(M_PI)/180, radius: radius-radiusSub)bigShine.add(bigAnim, forKey: "path")smallShine.add(smallAnim, forKey: "path")}let angleAnim = CABasicAnimation(keyPath: "transform.rotation")angleAnim.duration = params.animDuration * 0.87angleAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)angleAnim.fromValue = 0angleAnim.toValue = CGFloat(params.shineTurnAngle)*CGFloat(M_PI)/180angleAnim.delegate = selfadd(angleAnim, forKey: "rotate")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

四、最后再将这些动画通过一定规律结合起来

上图是将之前动画步骤组合起来后的效果,上面的一些代码只是部分代码,全部代码可以去我的github地址上去下在浏览,如果大家喜欢可以点一个start,有更好的想法也可以提出来,大家一起交流一下,最后谢谢大家阅读~~

iOS动画进阶 - 手摸手教你写ShineButton动画相关推荐

  1. 手摸手教你做动态壁纸

    手摸手教你做动态壁纸 Android · jeasonwong · 于 5 天前发布 · 最后由 xingstarx 于 2 天前回复 · 440 次阅读 项目地址:https://github.co ...

  2. 【万字长文】手摸手教你shell脚本编程

    [万字长文]手摸手教你shell脚本编程 我写这篇文章的目的 前段时间参加了联创团队的春令营, 为期半个多月的春令营做了三个项目, 其中有一个项目是关于shell的, 当时完全没接触过shell脚本编 ...

  3. 带你手摸手搭建vuepress站点

    vuePress是什么? VuePress 俺简单介绍下,是国内有名大神的尤雨溪发布的全新基于 vue 静态网站的生成器,内置的有 webpack组件,可以拿来写文档,主要是md格式.做出的感觉就是简 ...

  4. 短视频Gif快手-有点意思 | 手摸手产品研究院

    手摸手产品研究院是由PMCAFF发起的深度研究产品的产品经理精华小分队,旨在每天一起研究一款产品,并且由阿德老师手摸手指导写分析报告.                                 ...

  5. 手摸手,带你用vue撸后台 系列一(基础篇) - 掘金

    完整项目地址:vue-element-admin 系列文章: 手摸手,带你用 vue 撸后台 系列一(基础篇) 手摸手,带你用 vue 撸后台 系列二(登录权限篇) 手摸手,带你用 vue 撸后台 系 ...

  6. CSS —— 手摸手实现一个文字霓虹灯闪烁特效

    CSS -- 手摸手实现一个文字霓虹灯闪烁特效 一.了解 text-shadow 属性 text-shadow 属性应用于阴影文本,属于 CSS3 的属性,默认值为 none. text-shadow ...

  7. android videoview 拉伸,手摸手带你用 VideoView 实现英语流利说炫酷引导页

    效果图: 一直听说英语流利说是个做的非常不错的app,于是乎抱着崇拜的心态下了一个瞅瞅,在打开app后就被引导页吸引了,继续抱着崇拜的心态去思考这是如何实现的. 刚开始的思路属性动画?(可以实现,但是 ...

  8. 手摸手带你理解 进制 字节 ASCII码 Unicode 与 字节编码(UTF-8 /16)等(下)

    手摸手带你理解 进制 字节 ASCII码 Unicode 与 字节编码(UTF-8 /16)等(上) Unicode 先讲讲这个东西的规则 Unicode 通常(不是所有)用两个字节来表示 一个字符 ...

  9. 手摸手带你用实现vue全屏loading插件

    手摸手带你用实现vue全屏loading插件 前言: 由于我们打开网页时,浏览器与服务器交互需要时间,受限于宽带以及服务器性能,导致用户在访问一个网页时,往往需要一个等待期,才能在浏览器中真正完全展示 ...

最新文章

  1. 关于DOM的有关总结
  2. ElasticSearch知识汇总
  3. 【Network Security!】Linux中apt-get update和apt-get upgrade命令的区别
  4. 深入浅出 Java 中 JVM 内存管理
  5. PMcaff-产品 | 教你做好产品设计规范,提升工作效率
  6. “出题老师”超全划重点,赛场高分必备干货!
  7. JAVA基础——设计模式之观察者模式
  8. hex和base32和base64的区别与联系
  9. 产品分析之美团_米米米米粒口红_新浪博客
  10. Ubuntu系统上的ImageJ安装和卸载方法
  11. 程序员复试都准备什么_考研复试一般能过吗 主要都考什么
  12. 转:PV、UV、访问次数、跳出率、转化率、平均访问时长
  13. 原生js实现轮播图效果
  14. (深度学习评估指标)——MS COCO detection evaluation metrics
  15. cad放大_cad快捷键大全amp;鼠标各键用法
  16. ECharts 柱状图上显示数据,并自定义图标
  17. NCUT 数据库基础 铁路购票系统
  18. java文件长度_Java中的音频文件长度
  19. 函数getopt(),及其参数optind
  20. 张栋博士计算机,计算机科学与技术学院

热门文章

  1. centos7中使用yum安装tomcat以及它的启动、停止、重启
  2. crud springmvc
  3. Java12和Jdk12安装以及OpenJdk12源码
  4. 调用API弹出打印机属性对话框
  5. PHP5.5的一点变化
  6. 灰度图像直方图均衡化公式及实现
  7. tiny-cnn执行过程分析(MNIST)
  8. 【linux工具】ldconfig:linux配置动态链接库
  9. html在页面上div绝对定位,html – 中心浮动div在绝对定位div内
  10. 学计算机为什么会突发,为什么电脑会突然自动重启?