订阅移动开发RSS CSDN首页> 移动开发

iOS开发实践:用Swift和Core Animatoin创建圆形图片加载动画

发表于2015-06-12 10:30| 次阅读| 来源CSDN| 0 条评论| 作者刘耀柱

摘要:本文作者在文章中详细地讲解了如何使用Swift和Core Animatoin来创建将圆形进度指示器和圆形渐现动画相结合的动画效果。基于本教程,开发者还可以根据自己的需求和设计美学来进一步微调动画的时间、曲线和颜色等。

几个星期之前,Michael Villar在Motion试验中创建一个非常有趣的加载动画。下面的GIF图片展示这个加载动画,它将一个圆形进度指示器和圆形渐现动画结合。这个组合的效果有趣,独一无二和有点迷人。


这个教程将会教你如何使用Swift和Core Animatoin来重新创建这个效果,让我们开始吧!

基础

首先下载这个教程的启动项目,然后编译和运行。过一会之后,你应该看到一个简单的image显示:


这个启动项目已经预先在恰当的位置将views和加载逻辑编写好了。花一分钟来浏览来快速了解这个项目;那里有一个ViewController,ViewController里有一个命名为CustomImageView的UIImageView子类, 还有一个SDWebImage的方法被调用来加载image。

你可能注意到当你第一次运行这个app的时候,当image下载时这个app似乎会暂停几秒,然后image会显示在屏幕。当然,此刻没有圆形进度指示器 - 你将会在这个教程中创建它!

你会在两个步骤中创建这个动画:

  1. 圆形进度。首先,你会画一个圆形进度指示器,然后根据下载进度来更新它。
  2. 扩展圆形图片。第二,你会通过扩展的圆形窗口来揭示下载图片。

紧跟着下面步骤来逐步实现!

创建圆形指示器

想一下关于进度指示器的基本设计。这个指示器一开始是空来展示0%进度,然后逐渐填满直到image完成下载。通过设置CAShapeLayer的path为circle来实现是相当简单。

注意:如果你不熟悉CAShapeLayer(或CALayers)的基本概念,可以查看Scott Gardner的CALayer in iOS with Swift文章。

你可以通过CAShapeLayer的strokeStart和strokeEnd属性来控制开始和结束位置的外观。通过改变strokeEnd的值在0到1之间,你可以恰当地填充下载进度。

让我们试一下。通过iOS\Source\Cocoa Touch Class template来创建一个新的文件,文件名为CircularLoaderView。设置它为UIView的子类。


点击Next和Create。新的子类UIView将用来保存动画的代码。

打开CircularLoaderView.swift和添加以下属性和常量到这个类:

let circlePathLayer = CAShapeLayer()
let circleRadius: CGFloat = 20.0

circlePathLayer表示这个圆形路径,而circleRadius表示这个圆形路径的半径。

添加以下初始化代码到CircularLoaderView.swift来配置这个shape layer:

override init(frame: CGRect) {
  super.init(frame: frame)
  configure()
}

required init(coder aDecoder: NSCoder) {
  super.init(coder: aDecoder)
  configure()
}

func configure() {
  circlePathLayer.frame = bounds
  circlePathLayer.lineWidth = 2
  circlePathLayer.fillColor = UIColor.clearColor().CGColor
  circlePathLayer.strokeColor = UIColor.redColor().CGColor
  layer.addSublayer(circlePathLayer)
  backgroundColor = UIColor.whiteColor()
}

两个初始化方法都调用configure方法,configure方法设置一个shape layer的line width为2,fill color为clear,stroke color为red。将添加circlePathLayer添加到view's main layer。然后设置view的 backgroundColor 为white,那么当image加载时,屏幕的其余部分就忽略掉。

添加路径

你会注意到你还没赋值一个path给layer。为了做到这点,添加以下方法(还是在CircularLoaderView.swift文件):

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
}

上面那个方法返回一个CGRect的实例来界定指示器的路径。这个边框是2*circleRadius宽和2*circleRadius高,放在这个view的正中心。

每次这个view的size改变时,你会需要都重新计算circleFrame,所以你可能将它放在一个独立的方法。

现在添加以下方法来创建你的路径:

func circlePath() -> UIBezierPath {
  return UIBezierPath(ovalInRect: circleFrame())
}

这只是根据circleFrame限定来返回圆形的UIBezierPath。由于circleFrame()返回一个正方形,在这种情况下”椭圆“会最终成为一个圆形。

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

下一步,覆盖layoutSubviews()方法:

override func layoutSubviews() {
  super.layoutSubviews()
  circlePathLayer.frame = bounds
  circlePathLayer.path = circlePath().CGPath
}

由于改变了frame,你要在这里调用circlePath()方法来触发重新计算路径。

现在打开CustomImageView.swift文件和添加以下CircularLoaderView实例作为一个属性:

let progressIndicatorView = CircularLoaderView(frame: CGRectZero)

下一步,在之前下载图片的代码添加这几行代码到init(coder:)方法:

addSubview(self.progressIndicatorView)
progressIndicatorView.frame = bounds
progressIndicatorView.autoresizingMask = .FlexibleWidth | .FlexibleHeight

上面代码添加进度指示器作为一个subview添加到自定义的image view。autoresizingMask确保进度指示器view保持与image view的size一样。

0
0