demo.gif

如图,这个动画的是如何做的呢?

分析:

  • 1.环形进度指示器,根据下载进度来更新它
  • 2.扩展环,向内向外扩展这个环,中间扩展的时候,去掉这个遮盖

一.环形进度指示器

1.自定义View继承UIView,命名为CircularLoaderView.swift,此View将用来保存动画的代码

2.创建CAShapeLayer

  1. let circlePathLayer = CAShapeLayer()
  2. let circleRadius: CGFloat = 20.0

3.初始化CAShapeLayer

  1. // 两个初始化方法都调用configure方法
  2. override init(frame: CGRect) {
  3. super.init(frame: frame)
  4. configure()
  5. }
  6. required init?(coder aDecoder: NSCoder) {
  7. super.init(coder : aDecoder)
  8. configure()
  9. }
  10. // 初始化代码来配置这个shape layer:
  11. func configure(){
  12. circlePathLayer.frame = bounds;
  13. circlePathLayer.lineWidth = 2.0
  14. circlePathLayer.fillColor = UIColor.clearColor().CGColor
  15. circlePathLayer.strokeColor = UIColor.redColor().CGColor
  16. layer.addSublayer(circlePathLayer)
  17. backgroundColor = UIColor.whiteColor()
  18. // 初始化属性,后面用来监听图片下载进度
  19. progress = 0.0
  20. }

4.设置环形进度条的矩形frame

  1. // 小矩形的frame
  2. func circleFrame() -> CGRect {
  3. var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
  4. circleFrame.origin.x = CGRectGetMidX(circlePathLayer.bounds) - CGRectGetMidX(circleFrame)
  5. circleFrame.origin.y = CGRectGetMidY(circlePathLayer.bounds) - CGRectGetMidY(circleFrame)
  6. return circleFrame
  7. }

可以参考下图,理解这个circleFrame

Snip20160705_3.png

5.每次自定义的这个view的size改变时,你都需要重新计算circleFrame,所以要将它放在一个独立的方法,方便调用

  1. // 通过一个矩形(正方形)绘制椭圆(圆形)路径
  2. func circlePath() -> UIBezierPath {
  3. return UIBezierPath(ovalInRect: circleFrame())
  4. }

6.由于layers没有autoresizingMask这个属性,你需要在layoutSubviews方法中更新circlePathLayer的frame来恰当地响应view的size变化

  1. override func layoutSubviews() {
  2. super.layoutSubviews()
  3. circlePathLayer.frame = bounds
  4. circlePathLayer.path = circlePath().CGPath
  5. }

7.给CircularLoaderView.swift文件添加一个CGFloat类型属性,自定义的setter和getter方法,setter方法验证输入值要在0到1之间,然后赋值给layer的strokeEnd属性。

  1. var progress : CGFloat{
  2. get{
  3. return circlePathLayer.strokeEnd
  4. }
  5. set{
  6. if (newValue > 1) {
  7. circlePathLayer.strokeEnd = 1
  8. }else if(newValue < 0){
  9. circlePathLayer.strokeEnd = 0
  10. }else{
  11. circlePathLayer.strokeEnd = newValue
  12. }
  13. }
  14. }

8.利用SDWebImage,在image下载回调方法中更新progress.
此处是自定义ImageView,在storyboard中拖个ImageView,设置为自定义的ImageView类型,在这个ImageView初始化的时候就会调用下面的代码

  1. class CustomImageView: UIImageView {
  2. // 创建一个实例对象
  3. let progressIndicatorView = CircularLoaderView(frame: CGRectZero)
  4. required init?(coder aDecoder: NSCoder) {
  5. super.init(coder: aDecoder)
  6. addSubview(progressIndicatorView)
  7. progressIndicatorView.frame = bounds
  8. // 注意写法
  9. progressIndicatorView.autoresizingMask = [.FlexibleWidth , .FlexibleHeight]
  10. let url = NSURL(string: "http://www.raywenderlich.com/wp-content/uploads/2015/02/mac-glasses.jpeg")
  11. // 注意到block使用weak self引用 – 这样能够避免retain cycle
  12. self.sd_setImageWithURL(url, placeholderImage: nil, options: .CacheMemoryOnly, progress: { [weak self](reseivdSize, expectedSize) -> Void in
  13. self!.progressIndicatorView.progress = CGFloat(reseivdSize) / CGFloat(expectedSize)
  14. }) { [weak self](image, error, _, _) -> Void in
  15. // 下载完毕后,执行的动画
  16. self?.progressIndicatorView.reveal()
  17. }
  18. }
  19. }

二.扩展这个环

仔细看,此处是两个动画一起执行,1是向外扩展2.是向内扩展.但可以用一个Bezier path完成此动画,需要用到组动画.

  • 1.增加圆的半径(path属性)来向外扩展
  • 2.同时增加line的宽度(lineWidth属性)来使环更加厚和向内扩展
  1. func reveal() {
  2. // 背景透明,那么藏着后面的imageView将显示出来
  3. backgroundColor = UIColor.clearColor()
  4. progress = 1.0
  5. // 移除隐式动画,否则干扰reveal animation
  6. circlePathLayer.removeAnimationForKey("strokenEnd")
  7. // 从它的superLayer 移除circlePathLayer ,然后赋值给super的layer mask
  8. circlePathLayer.removeFromSuperlayer()
  9. // 通过这个这个circlePathLayer 的mask hole动画 ,image 逐渐可见
  10. superview?.layer.mask = circlePathLayer
  11. // 1 求出最终形状
  12. let center = CGPoint(x:CGRectGetMidX(bounds),y: CGRectGetMidY(bounds))
  13. let finalRadius = sqrt((center.x*center.x) + (center.y*center.y))
  14. let radiusInset = finalRadius - circleRadius
  15. let outerRect = CGRectInset(circleFrame(), -radiusInset, -radiusInset)
  16. // CAShapeLayer mask最终形状
  17. let toPath = UIBezierPath(ovalInRect: outerRect).CGPath
  18. // 2 初始值
  19. let fromPath = circlePathLayer.path
  20. let fromLineWidth = circlePathLayer.lineWidth
  21. // 3 最终值
  22. CATransaction.begin()
  23. // 防止动画完成跳回原始值
  24. CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
  25. circlePathLayer.lineWidth = 2 * finalRadius
  26. circlePathLayer.path = toPath
  27. CATransaction.commit()
  28. // 4 路径动画,lineWidth动画
  29. let lineWidthAnimation = CABasicAnimation(keyPath: "lineWidth")
  30. lineWidthAnimation.fromValue = fromLineWidth
  31. lineWidthAnimation.toValue = 2*finalRadius
  32. let pathAnimation = CABasicAnimation(keyPath: "path")
  33. pathAnimation.fromValue = fromPath
  34. pathAnimation.toValue = toPath
  35. // 5 组动画
  36. let groupAnimation = CAAnimationGroup()
  37. groupAnimation.duration = 1
  38. groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
  39. groupAnimation.animations = [pathAnimation ,lineWidthAnimation]
  40. groupAnimation.delegate = self
  41. circlePathLayer.addAnimation(groupAnimation, forKey: "strokeWidth")
  42. }

photo-loading-diagram.png

三.监听动画的结束

  1. // 移除mask
  2. override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
  3. superview?.layer.mask = nil;
  4. }

示例下载地址github
原文地址Rounak Jain
参考地址

文/船长_(简书作者)
原文链接:http://www.jianshu.com/p/a9d7e39c7312
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

iOS-swift环形进度指示器+图片加载动画的更多相关文章

  1. iOS开发——图形编程Swift篇&CAShapeLayer实现圆形图片加载动画

    CAShapeLayer实现圆形图片加载动画 几个星期之前,Michael Villar在Motion试验中创建一个非常有趣的加载动画. 下面的GIF图片展示这个加载动画,它将一个圆形进度指示器和圆形 ...

  2. 使用CAShapeLayer来实现圆形图片加载动画[译]

    原文链接 : How To Implement A Circular Image Loader Animation with CAShapeLayer 原文作者 : Rounak Jain 译文出自 ...

  3. CSS3实现的图片加载动画效果

    来源:GBin1.com 使用CSS3实现的不同图片加载动画效果,支持响应式,非常适合针对瀑布流布局图片动态加载特效进行增强! HTML <ul class="grid effect- ...

  4. https加载http资源,导致ios手机上的浏览器图片加载问题

    今天解决一个线上bug的时候发现的问题,如下图: 从表象来看,同样的图片,安卓手机上可以正常展示,但是到ios手机上首次进入页面就不能正常显示图片,必须手动刷新一次页面才能正常加载. 这时候,我们首先 ...

  5. 如何用Swift创建一个复杂的加载动画

    现在在苹果应用商店上有超过140万的App,想让你的app事件非常具有挑战的事情.你有这样一个机会,在你的应用的数据完全加载出来之前,你可以通过一个很小的窗口来捕获用户的关注. 没有比这个更好的地方让 ...

  6. iOS图片加载框架-SDWebImage解读

    在iOS的图片加载框架中,SDWebImage可谓是占据大半壁江山.它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件.在项目中使用SDWebImage ...

  7. iOS 图片加载框架- SDWebImage 解读

    在iOS的图片加载框架中,SDWebImage可谓是占据大半壁江山.它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件.在项目中使用SDWebImage ...

  8. iOS图片加载-SDWebImage

    一.SDWebImage内部实现过程 1, 入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后  SDWeb ...

  9. Vue回炉重造之图片加载性能优化

    前言 图片加载优化对于一个网站性能好坏起着至关重要的作用.所以我们使用Vue来操作一波.备注 以下的优化一.优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的 ...

随机推荐

  1. java学习随笔--- 捣蛋vector

    最近比较有时间啦,有时间搞下java,个人觉得学这门语言语法太多啦,不一一去学习啦,心血来潮,挂了个struct2的源代码,一入深似海啊,看得我天花缭乱,从最简单的开始吧 public static ...

  2. 本地虚拟机挂载windows共享目录搭建开发环境

    关闭防火墙(本地环境 直接关掉即可)service iptables stop检查是否安装了需要的samba软件包rpm –q samba如果没安装yum install samba system-c ...

  3. JS获得月最后一天和js得到一个月最大天数

    <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>标题页</title ...

  4. 【Siverlight - 扩展篇】Silverlight在OOB模式下实现默认打开最大化

      在App.xaml.cs中输入以下代码:在OOB客户端打开,可以实现窗口默认最大化: private void Application_Startup(object sender, Startup ...

  5. eCryptfs文件系统测试

    650) this.width=650;" onclick='window.open("http://blog.51cto.com/viewpic.php?refimg=" ...

  6. Hadoop构成

    What Is Apache Hadoop? The Apache™ Hadoop® project develops open-source software for reliable, scala ...

  7. 为什么数据科学家们选择了Python语言?

    本文由 伯乐在线 - HanSir 翻译,toolate 校稿 英文出处:Quora [伯乐在线导读]:这个问题来自 Quora,题主还补充说,“似乎很多搞数据的程序员都挺擅长 Python 的,这是 ...

  8. 【MySql】在Linux下安装MySql数据库

    [参数环境] 1.Host OS:Win7 64bit 2.VM: VMware 11.1.0 3.Client OS:CentOS 6 4.系统中已安装的openssl版本: openssl-1.0 ...

  9. Clean Code第三章<函数>

    1.方法不要写太长,如果太长,抽取其中的逻辑到新的方法中 bad good 2.函数只做一件事 如果做了多件事,要在方法名里体现出来 3.每个函数一个抽象层级 4.函数名可以长一些,比长注释好 5.方 ...

  10. B - Kefa and Company

    B - Kefa and Company Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I6 ...