iOS-swift环形进度指示器+图片加载动画
如图,这个动画的是如何做的呢?
分析:
- 1.环形进度指示器,根据下载进度来更新它
- 2.扩展环,向内向外扩展这个环,中间扩展的时候,去掉这个遮盖
一.环形进度指示器
1.自定义View继承UIView,命名为CircularLoaderView.swift,此View将用来保存动画的代码
2.创建CAShapeLayer
let circlePathLayer = CAShapeLayer()
let circleRadius: CGFloat = 20.0
3.初始化CAShapeLayer
// 两个初始化方法都调用configure方法
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder : aDecoder)
configure()
}
// 初始化代码来配置这个shape layer:
func configure(){
circlePathLayer.frame = bounds;
circlePathLayer.lineWidth = 2.0
circlePathLayer.fillColor = UIColor.clearColor().CGColor
circlePathLayer.strokeColor = UIColor.redColor().CGColor
layer.addSublayer(circlePathLayer)
backgroundColor = UIColor.whiteColor()
// 初始化属性,后面用来监听图片下载进度
progress = 0.0
}
4.设置环形进度条的矩形frame
// 小矩形的frame
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
circleFrame.origin.x = CGRectGetMidX(circlePathLayer.bounds) - CGRectGetMidX(circleFrame)
circleFrame.origin.y = CGRectGetMidY(circlePathLayer.bounds) - CGRectGetMidY(circleFrame)
return circleFrame
}
可以参考下图,理解这个circleFrame
5.每次自定义的这个view的size改变时,你都需要重新计算circleFrame,所以要将它放在一个独立的方法,方便调用
// 通过一个矩形(正方形)绘制椭圆(圆形)路径
func circlePath() -> UIBezierPath {
return UIBezierPath(ovalInRect: circleFrame())
}
6.由于layers没有autoresizingMask这个属性,你需要在layoutSubviews方法中更新circlePathLayer的frame来恰当地响应view的size变化
override func layoutSubviews() {
super.layoutSubviews()
circlePathLayer.frame = bounds
circlePathLayer.path = circlePath().CGPath
}
7.给CircularLoaderView.swift文件添加一个CGFloat
类型属性,自定义的setter和getter方法,setter方法验证输入值要在0到1之间,然后赋值给layer的strokeEnd属性。
var progress : CGFloat{
get{
return circlePathLayer.strokeEnd
}
set{
if (newValue > 1) {
circlePathLayer.strokeEnd = 1
}else if(newValue < 0){
circlePathLayer.strokeEnd = 0
}else{
circlePathLayer.strokeEnd = newValue
}
}
}
8.利用SDWebImage
,在image下载回调方法中更新progress.
此处是自定义ImageView,在storyboard中拖个ImageView,设置为自定义的ImageView类型,在这个ImageView初始化的时候就会调用下面的代码
class CustomImageView: UIImageView {
// 创建一个实例对象
let progressIndicatorView = CircularLoaderView(frame: CGRectZero)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(progressIndicatorView)
progressIndicatorView.frame = bounds
// 注意写法
progressIndicatorView.autoresizingMask = [.FlexibleWidth , .FlexibleHeight]
let url = NSURL(string: "http://www.raywenderlich.com/wp-content/uploads/2015/02/mac-glasses.jpeg")
// 注意到block使用weak self引用 – 这样能够避免retain cycle
self.sd_setImageWithURL(url, placeholderImage: nil, options: .CacheMemoryOnly, progress: { [weak self](reseivdSize, expectedSize) -> Void in
self!.progressIndicatorView.progress = CGFloat(reseivdSize) / CGFloat(expectedSize)
}) { [weak self](image, error, _, _) -> Void in
// 下载完毕后,执行的动画
self?.progressIndicatorView.reveal()
}
}
}
二.扩展这个环
仔细看,此处是两个动画一起执行,1是向外扩展2.是向内扩展.但可以用一个Bezier path完成此动画,需要用到组动画.
- 1.增加圆的半径(path属性)来向外扩展
- 2.同时增加line的宽度(lineWidth属性)来使环更加厚和向内扩展
func reveal() {
// 背景透明,那么藏着后面的imageView将显示出来
backgroundColor = UIColor.clearColor()
progress = 1.0
// 移除隐式动画,否则干扰reveal animation
circlePathLayer.removeAnimationForKey("strokenEnd")
// 从它的superLayer 移除circlePathLayer ,然后赋值给super的layer mask
circlePathLayer.removeFromSuperlayer()
// 通过这个这个circlePathLayer 的mask hole动画 ,image 逐渐可见
superview?.layer.mask = circlePathLayer
// 1 求出最终形状
let center = CGPoint(x:CGRectGetMidX(bounds),y: CGRectGetMidY(bounds))
let finalRadius = sqrt((center.x*center.x) + (center.y*center.y))
let radiusInset = finalRadius - circleRadius
let outerRect = CGRectInset(circleFrame(), -radiusInset, -radiusInset)
// CAShapeLayer mask最终形状
let toPath = UIBezierPath(ovalInRect: outerRect).CGPath
// 2 初始值
let fromPath = circlePathLayer.path
let fromLineWidth = circlePathLayer.lineWidth
// 3 最终值
CATransaction.begin()
// 防止动画完成跳回原始值
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
circlePathLayer.lineWidth = 2 * finalRadius
circlePathLayer.path = toPath
CATransaction.commit()
// 4 路径动画,lineWidth动画
let lineWidthAnimation = CABasicAnimation(keyPath: "lineWidth")
lineWidthAnimation.fromValue = fromLineWidth
lineWidthAnimation.toValue = 2*finalRadius
let pathAnimation = CABasicAnimation(keyPath: "path")
pathAnimation.fromValue = fromPath
pathAnimation.toValue = toPath
// 5 组动画
let groupAnimation = CAAnimationGroup()
groupAnimation.duration = 1
groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
groupAnimation.animations = [pathAnimation ,lineWidthAnimation]
groupAnimation.delegate = self
circlePathLayer.addAnimation(groupAnimation, forKey: "strokeWidth")
}
三.监听动画的结束
// 移除mask
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
superview?.layer.mask = nil;
}
示例下载地址github
原文地址Rounak Jain
参考地址
原文链接:http://www.jianshu.com/p/a9d7e39c7312
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
iOS-swift环形进度指示器+图片加载动画的更多相关文章
- iOS开发——图形编程Swift篇&CAShapeLayer实现圆形图片加载动画
CAShapeLayer实现圆形图片加载动画 几个星期之前,Michael Villar在Motion试验中创建一个非常有趣的加载动画. 下面的GIF图片展示这个加载动画,它将一个圆形进度指示器和圆形 ...
- 使用CAShapeLayer来实现圆形图片加载动画[译]
原文链接 : How To Implement A Circular Image Loader Animation with CAShapeLayer 原文作者 : Rounak Jain 译文出自 ...
- CSS3实现的图片加载动画效果
来源:GBin1.com 使用CSS3实现的不同图片加载动画效果,支持响应式,非常适合针对瀑布流布局图片动态加载特效进行增强! HTML <ul class="grid effect- ...
- https加载http资源,导致ios手机上的浏览器图片加载问题
今天解决一个线上bug的时候发现的问题,如下图: 从表象来看,同样的图片,安卓手机上可以正常展示,但是到ios手机上首次进入页面就不能正常显示图片,必须手动刷新一次页面才能正常加载. 这时候,我们首先 ...
- 如何用Swift创建一个复杂的加载动画
现在在苹果应用商店上有超过140万的App,想让你的app事件非常具有挑战的事情.你有这样一个机会,在你的应用的数据完全加载出来之前,你可以通过一个很小的窗口来捕获用户的关注. 没有比这个更好的地方让 ...
- iOS图片加载框架-SDWebImage解读
在iOS的图片加载框架中,SDWebImage可谓是占据大半壁江山.它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件.在项目中使用SDWebImage ...
- iOS 图片加载框架- SDWebImage 解读
在iOS的图片加载框架中,SDWebImage可谓是占据大半壁江山.它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件.在项目中使用SDWebImage ...
- iOS图片加载-SDWebImage
一.SDWebImage内部实现过程 1, 入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWeb ...
- Vue回炉重造之图片加载性能优化
前言 图片加载优化对于一个网站性能好坏起着至关重要的作用.所以我们使用Vue来操作一波.备注 以下的优化一.优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的 ...
随机推荐
- WebApp开发经验
1.自适应屏幕 <meta name="viewport" id="viewport" content="width = device-widt ...
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2038 [题意] 给定一个有颜色的序列,回答若干个询问:区间内任选两个颜色相同的概率. ...
- leetcode–jump game II
1.题目描述 Given an array of non-negative integers, you are initially positioned at the first index of t ...
- 怎样下载完整的Spring包
自从3.2版本以后,Spring不再提供包含所有库的文件下载了只有Sping自身的最基本库,所依赖的东西需要自己搞定首先, 这个链接 包含了Spring自身和所用到的所有东西 这个 是上述链接的说 ...
- [翻译]创建ASP.NET WebApi RESTful 服务(9)
一旦成功的发布API后,使用者将依赖于你所提供的服务.但是变更总是无法避免的,因此谨慎的制定ASP.NET Web API的版本策略就变得非常重要.一般来说,新的功能需要无缝的接入,有时新老版本需要并 ...
- POJ1463 Strategic game (最小点覆盖 or 树dp)
题目链接:http://poj.org/problem?id=1463 给你一棵树形图,问最少多少个点覆盖所有的边. 可以用树形dp做,任选一点,自底向上回溯更新. dp[i][0] 表示不选i点 覆 ...
- memcached在windows7上的安装问题
memcached在windows7上的安装问题 错误: 通过cmd命令行进入到C:\memcached(下载后的解压目录) 运行 memcached.exe -d install 报错“ f ...
- J2EE项目相对路径、绝对路径获取
String path = getServletContext().getRealPath("/"); 这将获取web项目的全路径. this.getClass().getClas ...
- magento目录结构精编版
1 /app – 程序根目录 2 3 /app/etc – 全局配置文件目录 4 5 /app/code – 所有模块安装其模型和控制器的目录 6 7 /app/code/core – 核心代码或经过 ...
- cf754 A. Lesha and array splitting
应该是做麻烦了,一开始还没A(幸好上一次比赛水惨了) #include<bits/stdc++.h> #define lowbit(x) x&(-x) #define LL lon ...