本文由CocoaChina译者@lisjCharles翻译自raywenderlich
原文:How to Create a Complex Loading Animation in Swift


时至今日,iOS 应用商店已经拥有超过了140万 应用,让你自己的应用脱颖而出确实是个不小的挑战。不过,在你的应用掉入默默无闻的大黑洞之前,你拥有一个小小的机遇窗,它能帮你吸引用户的注意。

想让你的用户喝彩尖叫,没有比应用加载界面更好的地方 ,在这个地方,你可以添加一个讨人喜欢的动画来作为你登陆或者认证流程的先导。

在这个教程中,你将要学会如何利用先进的技术来创建一个流畅并且迷人的动画。

开始吧!!


从这里下载启动项目,保存在一个合适的路径并用Xcode打开。

打开 HolderView.swift 。 在这个UIView 的子类中,你可以添加些子层(在Layers的下级目录中可以找到),使之像上面的动画一样生动

ovalLayer.swift:这是第一层,它从零尺寸扩展,然后会有一小段时间的摇摆

TriangleLayer.swift:接下来的这个层TriangleLayer会在ovalLayer 摇摆的时候出现,当此视图转动时,ovalLayer 会缩小到零尺寸,并在TriangleLayer 中消失。

RectangleLayer.swift:这个层是TriangleLayer 用于分类的可视化容器

ArcLayer.swift:这个层动画特效填充在RectangleLayer 中,这和杯子里填充了水(效果)非常相似

打开ovalLayer.swift,启动项目已经包含了用于初始化这个层的代码和所有你会在动画里用到的Bezier path(对象)。你会看到expand(),wobble()和contract()方法都是空的。你可以通过参考这个指导书来填充这些方法。所有其他的 *Layer (以layer结尾)的文件都用了相似的方式构建。

注意:如果你想要学习更多的Bezier paths,那就检出我们系列指导书Modern Core Graphics with Swift

最后,打开ViewController.swift 查看addHolderView()方法,这个方法添加了一个HolderView 作为一个子视图,放到viewcontroller 视图的中间。这个视图将会放置所有的动画。viewcontroller仅仅需要把它放到屏幕上,这个视图将会照管好现行的动画代码。

animateLabel() 是由类 HolderView 提供的代理回调函数,此类中你会用你完成的动画序列来填充。addButton()方法只是添加一个按钮到视图中,用于触摸和重启动画。

编译并运行你的应用;你会看到一个空白屏幕。一个空白的画布--这就是用于开始创建你的新动画的完美的载体。在指导书的最后,你的应用会看起来是这样的:

现在不需再费周折,我们开始吧

添加一个椭圆


这个动画从一个椭圆开始,椭圆是从屏幕中间扩展到视图,然后在周围有点摇摆。

打开 HolderView.swift,在 HolderView 类的顶端附近声明如下的常量

1
letovalLayer=ovalLayer()

现在在此类的底部添加如下方法

1
2
3
4
funcaddoval(){
layer.addSublayer(ovalLayer)
ovalLayer.expand()
}

这段代码首先添加了你上面创建的 OverLayer 的实例作为一个子层到视图层,然后调用 expand() 方法,这是被切掉的需要你来填充的函数之一

来到 ovalLayer.swift 文件,添加如下代码到 expand() 中:

4
5
6
7
8
9
funcexpand(){
var expandAnimation:CABasicAnimation=CABasicAnimation(keyPath: "path" )
expandAnimation.fromValue=ovalPathSmall.CGPath
expandAnimation.tovalue=ovalPathLarge.CGPath
expandAnimation.duration=animationDuration
expandAnimation.fillMode=kCAFillModeForwards
expandAnimation.removedOnCompletion= false
addAnimation(expandAnimation,forKey:nil)
这个函数创建了一个 CABasicAnimation 的实例,这个实例用于改变椭圆从 ovalPathLarge.到 ovalPathSmall 的路径。启动项目为你提供了两者的Bezier paths。

设置动画的 removedOnCompletion 的值为 false,fillMode 的值为 KCAFillModeForwards ,使得当动画结束的时候,椭圆保留它新的路径。

最后,打开 ViewController.swift ,在 view.addSubview(holderView) 下的 addHolderView() 方法中添加如下的线条

holderView.addoval()

将 holdview 添加到 ViewController 的视图中后,调用 addoval 方法来启动动画

构建并运行你的应用,你的动画现在就会看起来像下面(图例)

摇动椭圆


使用视图中扩张的椭圆,下一步就是在椭圆的步调中设置一些反弹,使之摇摆起来

打开 HolderView.swift,在此类的底部,添加下面的函数

3
funcwobbleoval(){
ovalLayer.wobble()
在 ovalLayer 中调用被切掉的方法 wobble().

现在打开 OverLayer.swift,在 wobble() 中添加如下代码

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
funcwobble(){
//1
wobbleAnimation1:CABasicAnimation=CABasicAnimation(keyPath: )
wobbleAnimation1.fromValue=ovalPathLarge.CGPath
wobbleAnimation1.tovalue=ovalPathSquishVertical.CGPath
wobbleAnimation1.beginTime=0.0
wobbleAnimation1.duration=animationDuration
//2
wobbleAnimation2:CABasicAnimation=CABasicAnimation(keyPath: )
wobbleAnimation2.fromValue=ovalPathSquishVertical.CGPath
wobbleAnimation2.tovalue=ovalPathSquishHorizontal.CGPath
wobbleAnimation2.beginTime=wobbleAnimation1.beginTime+wobbleAnimation1.duration
wobbleAnimation2.duration=animationDuration
//3
wobbleAnimation3:CABasicAnimation=CABasicAnimation(keyPath: )
wobbleAnimation3.fromValue=ovalPathSquishHorizontal.CGPath
wobbleAnimation3.tovalue=ovalPathSquishVertical.CGPath
wobbleAnimation3.beginTime=wobbleAnimation2.beginTime+wobbleAnimation2.duration
wobbleAnimation3.duration=animationDuration
//4
wobbleAnimation4:CABasicAnimation=CABasicAnimation(keyPath: )
wobbleAnimation4.fromValue=ovalPathSquishVertical.CGPath
wobbleAnimation4.tovalue=ovalPathLarge.CGPath
wobbleAnimation4.beginTime=wobbleAnimation3.beginTime+wobbleAnimation3.duration
wobbleAnimation4.duration=animationDuration
//5
wobbleAnimationGroup:CAAnimationGroup=CAAnimationGroup()
wobbleAnimationGroup.animations=[wobbleAnimation1,wobbleAnimation2,wobbleAnimation3,
wobbleAnimation4]
wobbleAnimationGroup.duration=wobbleAnimation4.beginTime+wobbleAnimation4.duration
wobbleAnimationGroup.repeatCount=2
addAnimation(wobbleAnimationGroup,forKey:nil)
代码真够多的。但断句还是很讲究的。 接下来要做的是:

1.从大路径下降到被垂直压扁的动画

2.从垂直压扁变成水平和垂直都压扁

3.和垂直挤压(动画)切换

4.回到大路径结束动画

5.把你所有的动画合并到CAAnimationGroup组,并把这个动画组添加到你的 ovalLayout 中。

每一个随后的动画的 beginTime 都是其前一个动画和动画持续时间的 beginTime 总和。你重复动画组两次就会给你一种摆动出稍微拉长的感觉

尽管你现在拥有产生摇摆动画的所有代码,你还是不能调用你的新动画

我们回到 HolderView.swift,在 addoval() 结尾处添加如下代码

2
NSTimer.scheduledTimerWithTimeInterval(0.3,target:self,selector: "wobbleoval" ,
userInfo:nil,repeats: false )

在这里,你创建了一个timer定时器,它会在ovalLayer已经结束扩张后调用 wobbleoval()

编译并运行你的应用,检查下你的新动画。

这有点微妙,但那对一个真正的明快的动画是一个重要的因素。你不再需要那些满屏幕都是乱飞的东西了。

开始变身


是时候来电有趣的东西了。你将要把一个椭圆变身成为一个三角形。在用户眼里,这个转变应该看上去无缝连接的。要做到这些,你会用到两个相同颜色的分离的形状。

打开HolderView.swift,在HolderView类的顶端稍微靠近你早些时候添加的 ovalLayer 属性的下面添加如下代码

lettriangleLayer=TriangleLayer()

这里声明了一个 TriangleLayer 类的常量,正如你在 ovalLayer 中做的一样

现在,让wobbleoval()方法看上去像这样:

11
layer.addSublayer(triangleLayer) //Addthisline
ovalLayer.wobble()
//2
//Addthecodebelow
NSTimer.scheduledTimerWithTimeInterval(0.9,
selector: "drawAnimatedTriangle" ottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; font-family:Consolas,userInfo:nil,
repeats: )
上面的代码做了如下这些事情:
  1. 这行(代码)添加了一个 TiangleLayer 实例,这个实例在稍早的时候作为HolderView层的子层已经被初始化过了。

  2. 正如你所知道的,因为这个摇摆动画在1.8s的总间隔时间内运行两次,所以在中间点启动变形过程会是一个非常好的地方。因此,你要添加一个定时器timer,它在延迟0.9s之后执行drawAnimatedTriangle()

注意:找到动画的正确的间隔或延迟需要反复实验,这也是一个好的动画和一个极好的动画区别。我鼓励你去修补你的动画,让它们看上去完美。这可能要花点时间,但确是值得的。

接下来,在此类的底部添加如下的函数。

funcdrawAnimatedTriangle(){
triangleLayer.animate()
这个方法会被你刚刚加入到 wobbleoval() 中的timer定时器调用。

现在打开 TriangleLayer.swift,添加如下代码到 animate()

27
funcanimate(){
triangleAnimationLeft:CABasicAnimation=CABasicAnimation(keyPath: triangleAnimationLeft.fromValue=trianglePathSmall.CGPath
triangleAnimationLeft.tovalue=trianglePathLeftExtension.CGPath
triangleAnimationLeft.beginTime=0.0
triangleAnimationLeft.duration=0.3
triangleAnimationRight:CABasicAnimation=CABasicAnimation(keyPath: )
triangleAnimationRight.fromValue=trianglePathLeftExtension.CGPath
triangleAnimationRight.tovalue=trianglePathRightExtension.CGPath
triangleAnimationRight.beginTime=triangleAnimationLeft.beginTime+triangleAnimationLeft.duration
triangleAnimationRight.duration=0.25
triangleAnimationTop:CABasicAnimation=CABasicAnimation(keyPath: )
triangleAnimationTop.fromValue=trianglePathRightExtension.CGPath
triangleAnimationTop.tovalue=trianglePathTopExtension.CGPath
triangleAnimationTop.beginTime=triangleAnimationRight.beginTime+triangleAnimationRight.duration
triangleAnimationTop.duration=0.20
triangleAnimationGroup:CAAnimationGroup=CAAnimationGroup()
triangleAnimationGroup.animations=[triangleAnimationLeft,triangleAnimationRight,
triangleAnimationTop]
triangleAnimationGroup.duration=triangleAnimationTop.beginTime+triangleAnimationTop.duration
triangleAnimationGroup.fillMode=kCAFillModeForwards
triangleAnimationGroup.removedOnCompletion= false
addAnimation(triangleAnimationGroup,forKey:nil)
这段代码使三角层TriangleLayer的角一个挨一个的被弹拉成为椭圆 ovalLayer 层的摆动。Bezier path已经作为启动工程的一部分被定义好。左边的角首先执行,接下来是右边的角,最后是上面的。你完成这个(动画)需要借助创建三个基于路径的CABasicAnimation类的实例, CABasicAnimation 类已经被你添加到 CAAnimationGroup 组中,而组则被放到了 TriangleLayer 中。

构建并运行你的应用,看看当前动画的状态.

完成变形


为了完成变形过程,你需要在缩小ovalLayer椭圆层的同时,对 HolderView 旋转360度,让 TriangleLayer 三角层单独隔离出来。

ottom:20px; padding-top:0px; padding-bottom:0px; color:rgb(37,在 drawAnimatedTriangle(): 尾部添加如下代码

"spinAndTransform" 这里设置了一个定时器timer,用于在三角形动画结束后触发。0.9s的时间还次用反复实验来确定

现在在这个类的底部添加如下的函数。

14
funcspinAndTransform(){
layer.anchorPoint=CGPointMake(0.5,0.6)
//2
rotationAnimation:CABasicAnimation=CABasicAnimation(keyPath: "transform.rotation.z" )
rotationAnimation.tovalue=CGFloat(M_PI*2.0)
rotationAnimation.duration=0.45
rotationAnimation.removedOnCompletion= true
layer.addAnimation(rotationAnimation,forKey:nil)
//3
ovalLayer.contract()
你之前创建的定时器添加了这段代码,定时器会在椭圆停止摆动并且三角行的角出现的时候调用这个函数。在这里我们看下这个函数更详细的(介绍)
  1. 更新层的锚点到略微靠近视图中间的下方。这提供了一个看上去更加自然的旋转。这是由于椭圆和三角形事实上比视图中心在垂直方向上略微偏移。因此,如果视图围绕中心旋转,椭圆和三角形可能会垂直方向移动

  2. 应用一个CABasicAnimation类来对层做360度旋转,或者2*pi的弧度。旋转是围绕着Z轴,Z轴就是穿过屏幕,垂直于屏幕平面的轴

  3. 在ovalLayer中调用contract()来展示动画,这个动画会削减椭圆的尺寸直到消失

现在打开 ovalLayer.swift,添加如下代码到 contract() 方法

funccontract(){
contractAnimation:CABasicAnimation=CABasicAnimation(keyPath: contractAnimation.fromValue=ovalPathLarge.CGPath
contractAnimation.tovalue=ovalPathSmall.CGPath
contractAnimation.duration=animationDuration
contractAnimation.fillMode=kCAFillModeForwards
contractAnimation.removedOnCompletion= addAnimation(contractAnimation,serif; font-size:14px; line-height:28px"> 这段代码应用 CABasicAnimation 类,将 ovalLayer 设置它的初始路径 ovalPathSmall。

构建并运行你的应用程序,当动画完成的时候,只有三角形应该被留在屏幕上。

绘制容器


在下面这部分,你将要绘画一个矩形容器,用于创建一个闭合圈。你将会用到 RectangleLayer 的描边属性。你需要这样做两次,将红色和蓝色都作为描边色。

ottom:20px; padding-top:0px; padding-bottom:0px; color:rgb(37,像下面这样声明两个 RectangularLayer 常量,(位置)就在你稍早时候 triangleLayer 属性的下面

letredRectangleLayer=RectangleLayer()letblueRectangleLayer=RectangleLayer()

接下来添加如下代码到 spinAndTransform(): 的尾部。

6
NSTimer.scheduledTimerWithTimeInterval(0.45,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"drawRedAnimatedRectangle" ottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; font-family:Consolas,
)
NSTimer.scheduledTimerWithTimeInterval(0.65,
"drawBlueAnimatedRectangle" ottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; font-family:Consolas,
这里创建两个定时器timer分别调用 drawRedAnimatedRectangle() 和 drawBlueAnimatedRectangle() 。旋转动画结束后,首先需要画出矩形,当红色矩形描边绘画接近完成的时候,蓝色矩形描边开始。

添加下面两个方法头此类的底部

funcdrawRedAnimatedRectangle(){
layer.addSublayer(redRectangleLayer)
redRectangleLayer.animatestrokeWithColor(Colors.red)
}
funcdrawBlueAnimatedRectangle(){
layer.addSublayer(blueRectangleLayer)
blueRectangleLayer.animatestrokeWithColor(Colors.blue)
一旦你添加矩形层 RectangleLayer 作为 HolderView 的子层,你就要调用 animatestrokeWithColor(color:) 并通过适当的颜色来绘画出边线。

现在打开 RectangleLayer.swift,像下面这样填充 animatestrokeWithColor(color:)

8
funcanimatestrokeWithColor(color:UIColor){
strokeColor=color.CGColor
strokeAnimation:CABasicAnimation=CABasicAnimation(keyPath: "strokeEnd" strokeAnimation.fromValue=0.0
strokeAnimation.tovalue=1.0
strokeAnimation.duration=0.4
addAnimation(strokeAnimation,forKey:nil)
这段代码通过添加一个 CABasicAnimation对象,在 RectangleLayer 矩形层周围绘画了一个描边。CAShapeLayer 的 strokeEnd 的 key(也就是keyPath)指示了在路径周围多远的距离停止描边。通过将这个属性值从0调到1,你会产生一种路径被从开始到结束都被绘画的错觉。 而从1到0,将会产生整个路径被抹去的错觉。

编译并运行你的应用,查看两个描边是如何看起来像他们构建的容器的。

填充容器


动画的下一步就是填充容器。你要寻找到的效果就像是水填充到玻璃杯中。这是个非常棒的视觉特效,使之为一个大的飞溅特效

ottom:20px; padding-top:0px; padding-bottom:0px; color:rgb(37,在 RectangleLayer 属性稍靠下添加如下的常量

letarcLayer=ArcLayer()

现在在drawBlueAnimatedRectangle():尾部添加如下的代码

NSTimer.scheduledTimerWithTimeInterval(0.40,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"drawArc" 这(段代码)创建了一个定时器,用于当蓝色 RectangleLayer 完成绘画后调用 drawArc()

在类的结尾添加如下的函数

funcdrawArc(){
layer.addSublayer(arcLayer)
arcLayer.animate()
这段代码是在你动画填充之前,添加了上面已经创建ArcLayer 的实例对象到HolderView 层。

打开ArcLayer.swift 然后添加如下代码到animate():

37
38
39
arcAnimationPre:CABasicAnimation=CABasicAnimation(keyPath: arcAnimationPre.fromValue=arcPathPre.CGPath
arcAnimationPre.tovalue=arcPathStarting.CGPath
arcAnimationPre.beginTime=0.0
arcAnimationPre.duration=animationDuration
arcAnimationLow:CABasicAnimation=CABasicAnimation(keyPath: arcAnimationLow.fromValue=arcPathStarting.CGPath
arcAnimationLow.tovalue=arcPathLow.CGPath
arcAnimationLow.beginTime=arcAnimationPre.beginTime+arcAnimationPre.duration
arcAnimationLow.duration=animationDuration
arcAnimationMid:CABasicAnimation=CABasicAnimation(keyPath: arcAnimationMid.fromValue=arcPathLow.CGPath
arcAnimationMid.tovalue=arcPathMid.CGPath
arcAnimationMid.beginTime=arcAnimationLow.beginTime+arcAnimationLow.duration
arcAnimationMid.duration=animationDuration
arcAnimationHigh:CABasicAnimation=CABasicAnimation(keyPath: )
arcAnimationHigh.fromValue=arcPathMid.CGPath
arcAnimationHigh.tovalue=arcPathHigh.CGPath
arcAnimationHigh.beginTime=arcAnimationMid.beginTime+arcAnimationMid.duration
arcAnimationHigh.duration=animationDuration
arcAnimationComplete:CABasicAnimation=CABasicAnimation(keyPath: )
arcAnimationComplete.fromValue=arcPathHigh.CGPath
arcAnimationComplete.tovalue=arcPathComplete.CGPath
arcAnimationComplete.beginTime=arcAnimationHigh.beginTime+arcAnimationHigh.duration
arcAnimationComplete.duration=animationDuration
arcAnimationGroup:CAAnimationGroup=CAAnimationGroup()
arcAnimationGroup.animations=[arcAnimationPre,arcAnimationLow,arcAnimationMid,
arcAnimationHigh,arcAnimationComplete]
arcAnimationGroup.duration=arcAnimationComplete.beginTime+arcAnimationComplete.duration
arcAnimationGroup.fillMode=kCAFillModeForwards
arcAnimationGroup.removedOnCompletion= false
addAnimation(arcAnimationGroup,forKey:nil)
这个动画和之前的摇摆动画很相似。你创建了一个 CAAnimationGroup 动画组,动画组中包含五个基于路径的 CABasicAnimation 实例对象。

每个路径因高度递增而有了稍微不同的弧,这些路径也是启动项目的一部分。最后,将 CAAnimationGroup 动画组应用到层中,并使得动画组在完成的时候不会被移除,因而当动画完成的时候,它依然保留了自己的状态。

构建并运行你的应用,看看这个神奇的展开吧。

完成动画


剩下要做的就是扩展蓝色的HolderView视图来填充整个屏幕,并且添加一个UILabel作为一个logo添加到视图中

打开 HolderView.swift,在drawArc() 的结尾添加如下代码

NSTimer.scheduledTimerWithTimeInterval(0.90,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"expandView" 这(段代码)创建了一个定时器,用于在 ArcLayer 填充到容器后调用 expandView()

现在,添加下面的函数到同一个类的底部:

21
funcexpandView(){
backgroundColor=Colors.blue
frame=CGRectMake(frame.origin.x-blueRectangleLayer.linewidth,
frame.origin.y-blueRectangleLayer.linewidth,
frame.size.width+blueRectangleLayer.linewidth*2,monospace!important; font-size:1em!important; min-height:inherit!important">frame.size.height+blueRectangleLayer.linewidth*2)
//3
layer.sublayers=nil
//4
UIView.animateWithDuration(0.3,delay:0.0,options:UIViewAnimationoptions.CurveEaseInOut,
animations:{
self.frame=self.parentFrame
},completion:{finished in
self.addLabel()
})
代码分析
  1. HolderView视图的背景设置为蓝色,和你填充到矩形的颜色匹配

  2. 帧扩展到你稍早时候添加的RectangleLayer矩形层的描边宽度,

  3. 所有的子层都移除。现在没有了椭圆,没有了三角形,没有了矩形图层

  4. 添加动画,并扩张HolderView填充屏幕,当动画结束的时候,调用addLabel().

在类的底部,添加如下函数

funcaddLabel(){
delegate?.animateLabel()
这里只是简单的调用视图的代理函数,展示label标签。

现在打开ViewController.swift,添加如下代码到animateLabel():

22
funcanimateLabel(){
holderView.removeFromSuperview()
view.backgroundColor=Colors.blue
label:UILabel=UILabel(frame:view.frame)
label.textColor=Colors.white
label.font=UIFont(name: "HelveticaNeue-Thin" ottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; font-family:Consolas,size:170.0)
label.textAlignment=NSTextAlignment.Center
label.text= "S"
label.transform=CGAffineTransformScale(label.transform,0.25,0.25)
view.addSubview(label)
//3
UIView.animateWithDuration(0.4,usingSpringWithdamping:0.7,initialSpringVeLocity:0.1,
animations:({
ottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; font-family:Consolas,4.0,4.0)
}),153)!important">in
self.addButton()
})
依次带入各个注释段
  1. 从视图中移除HolderView ,并设置视图的背景颜色为蓝色。

  2. 创建一个文本为"S"的UIlabel标签对象,用于展示logo,并添加到视图。

  3. 标签对象使用一个弹性动画来使之伸缩。一旦动画结束,调用 addButton() 来添加一个按钮到视图中,当按钮按下的时候,重复动画。

构建并运行应用程序,给自己点个赞,花个时间来欣赏自己构建的动画吧。

下一步


你可以从这里下载最终完整的项目。

这个指导书包含了相当多的不一样的动画技术,当这些动画都堆叠在一起的时候,能够创造一个相当复杂的加载动画,这确实能够让你的应用在第一次被(用户)运行的时候就眼前一亮。

从这里,放松自由的玩玩不一样的(动画 的)定时和形状,看看你能组装成哪些很酷的动画

如果你想让你新发现的动画技术提升一个档次,那我建议你看下我们的(这本)书iOS Animations by Tutorials.

我希望通过这本指导书你能得到极大的乐趣,并且,如果你有任何问题或者建议,请加入我们下面的论坛讨论吧

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


效率成吨提升之代码生成器-蓝湖工具神器iOS,Android,Swift,Flutter
软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
【Audio音频开发】音频基础知识及PCM技术详解
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
见过仙女蹦迪吗?一起用python做个小仙女代码蹦迪视频
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
自定义ava数据集及训练与测试 完整版 时空动作/行为 视频数据集制作 yolov5, deep sort, VIA MMAction, SlowFast
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
【视频+源码】登录鉴权的三种方式:token、jwt、session实战分享
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App附源码和演示视频 超详细必看
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
采用MATLAB对正弦信号,语音信号进行生成、采样和恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
Keras深度学习实战40——音频生成
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
  • • 效率成吨提升之代码生成器-蓝湖工具神器…
  • • 【Audio音频开发】音频基础知识及PCM技…
  • • 见过仙女蹦迪吗?一起用python做个小仙…
  • • 【Android App】实战项目之仿抖音的短视…
  • • 自定义ava数据集及训练与测试 完整版 时…
  • • 【视频+源码】登录鉴权的三种方式:tok…
  • • 【Android App】实战项目之仿微信的私信…
  • • 零基础用Android Studio实现简单的本地…
  • • 采用MATLAB对正弦信号,语音信号进行生…
  • • Keras深度学习实战40——音频生成
  • • 视频实时行为检测——基于yolov5+deeps…
  • • 数电实验 数字电子钟设计 基于quartus …
  • • 腾讯会议使用OBS虚拟摄像头
  • • 文本生成视频Make-A-Video,根据一句话…
  • • 信号处理——MATLAB音频信号加噪、滤波
  • • 【新知实验室 - TRTC 实践】音视频互动…
  • • Keras深度学习实战39——音乐音频分类
  • • C++游戏game | 井字棋游戏坤坤版配资源…

【实例教程】你会用swift创建复杂的加载动画吗的更多相关文章

  1. Canvas实现贝赛尔曲线轨迹动画的示例代码

    这篇文章主要介绍了Canvas实现贝赛尔曲线轨迹动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5 直播疯狂点赞动画实现代码 附源码

    为了烘托直播间的氛围,直播相对于普通视频或者文本内容,点赞动作通常无限次,引导用户疯狂点赞,今天小编给大家分享HTML5 直播疯狂点赞动画实现代码 附源码,感兴趣的朋友一起看看吧

  3. CSS中实现动画效果-附案例

    这篇文章主要介绍了 CSS中实现动画效果并附上案例代码及实现效果,就是CSS动画样式处理,动画声明需要使用@keyframes name,后面的name是人为定义的动画名称,下面我们来看看文章的具体实现内容吧,需要的小伙伴可以参考一下

  4. 基于canvas的骨骼动画的示例代码

    这篇文章主要介绍了基于canvas的骨骼动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. html5如何在Canvas中实现自定义路径动画示例

    本篇文章主要介绍了html5如何在Canvas中实现自定义路径动画示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  6. 基于HTML5+Webkit实现树叶飘落动画

    本文给大家分享一段实例代码给大家介绍基于HTML5+Webkit实现树叶飘落动画效果,需要的朋友参考下吧

  7. Html5页面内使用JSON动画的实现

    这篇文章主要介绍了Html5页面内使用JSON动画的实现的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. html5实现图片转圈的动画效果——让页面动起来

    这篇文章主要介绍了html5实现图片转圈的动画效果——让页面动起来的相关资料,需要的朋友可以参考下

  9. 基于 HTML5 WebGL 实现的医疗物流系统

    物联网( IoT ),简单的理解就是物体之间通过互联网进行链接。这篇文章给大家介绍基于 HTML5 WebGL 实现的医疗物流系统,感兴趣的朋友跟随小编一起看看吧

  10. ios – 仅在异步函数完成执行后运行代码

    所以,例如:如果问题是你不知道要调用什么函数,你可以配置你周围的函数/对象,这样有人可以给你一个函数,然后你在我上面说“调用函数”的地方调用你的函数.例如:

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部