CALayer Animation实践:iPhone经典滑动解锁动画

更新时间:2015-09-23 10:15:39 点击次数:3018次

在很多人的心目中iPhone的经典机型应该是iPhone4,精湛的工艺、完美的屏幕配上暗色的锁屏壁纸,看着屏幕底部闪烁的slide to unlock字样,高逼格彰显无遗。时至今日无论iPhone机身样式如何改变,屏幕尺寸如何改变,iOS系统如何改变,唯有锁屏底部闪烁的滑动来解锁不变。它的动画效果是如何实现的呢,这篇文章会告诉你们答案。

CAGradientLayer

新建一个应用名为GradientAnimation,打开Main.storyboard,将ViewController的View背景色设置为灰黑色,拖一个UIView到ViewController中,将其颜色设置为无色并设置好布局约束:

 

接着我们拖一个UILabel到刚才拖入的UIView中,设置高宽等同于它的父视图:

 

我对该UILabel的属性设置如下:

 

之后,我们在ViewController中添加UIView和UILabel的Outlet:

 

接下来回到ViewController.swift,我们添加一个常量属性gradientLayer


[cpp] view plaincopy

  1. let gradientLayer = CAGradientLayer()  


这里出现了CALayer的另一个子类CAGradientLayer,这个类的作用就是能在Layer上绘制出渐变颜色的效果,然后在viewDidLoad()中添加如下代码:


[cpp] view plaincopy

  1. gradientLayer.bounds = CGRect(x: 0, y: 0, width: backgroundView.frame.size.width, height: backgroundView.frame.size.height)  

  2. gradientLayer.position = CGPoint(x: backgroundView.frame.size.width/2, y: backgroundView.frame.size.height/2)  


上述两行的代码是设置Layer的大小及位置,这在上两篇文章中已经讲过,这里就不再累赘了。接着我们继续添加两行代码:


[cpp] view plaincopy

  1. gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)  

  2. gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)  


既然CAGradientLayer可以绘制出渐变颜色的效果,那自然有颜色渐变的方向,所以这两行代码的作用就是设置颜色渐变的起始点和结束点,这两个属性共同决定了颜色渐变的方向:

 

从上面的示意图中可以看出,CAGradientLayer是通过起始点和结束点的坐标位置来决定颜色渐变的方向的,起始点的默认值是(0.5, 0),结束点的默认值是(0.5, 1),也就是说默认的颜色渐变方向是沿垂直中线从上往下渐变的,我们在这里将它改成了沿水平中线从左往右渐变。

接下来我们设置CAGradientLayer的渐变颜色,接着添加如下代码:


[cpp] view plaincopy

  1. gradientLayer.colors = [  

  2.     UIColor.blackColor().CGColor,  

  3.     UIColor.whiteColor().CGColor,  

  4.     UIColor.blackColor().CGColor  

  5. ]  


CAGradientLayer的colors属性类型是一个数组[AnyObject],这就意味着我们可以实现多个颜色的渐变效果,并且可以规定各个颜色的顺序。不过在我们这个示例中我们只需要两种颜色,不过需要注意的是虽然颜色只有两种,但是整个颜色渐变的过程中有三个原色点,那就是黑、白、黑,所以我们在这个数组中也需要按照原色点的数量和顺序添加相应的颜色,哪怕颜色都是一样的。

我们既然设置了渐变的三个原色,那么就要对这原色出现的位置进行设置,接着添加如下代码:


[cpp] view plaincopy

  1. gradientLayer.locations = [0.2, 0.5, 0.8]  


从上述代码中不难看出,我们将个黑色原色出现的位置设置在了整个Layer长度的十分之二的位置,第二个白色原色在中间,第三个黑色原色在十分之八的位置:

 

设置完CAGradientLayer的相关属性后,我们将gradientLayer添加到backgroundView的Layer中:


[cpp] view plaincopy

  1. backgroundView.layer.addSublayer(gradientLayer)  


现在我们编译运行一下代码看看效果:


接下来我们需要让颜色渐变动起来,先创建一个方法gradinetAnimate(),在方法中添加如下代码:


[cpp] view plaincopy

  1. let gradient = CABasicAnimation(keyPath: "locations")  

  2. gradient.fromValue = [0, 0, 0.25]  

  3. gradient.toValue = [0.75, 1, 1]  

  4. gradient.duration = 2.5  

  5. gradient.repeatCount = HUGE  

  6. gradientLayer.addAnimation(gradient, forKey: nil)  


首先,创建了一个locations类型的动画实例gradient,将fromValue属性,也就是起始位置的属性设置为[0, 0, 0.25],它的意思是动画开始前,黑色、白色这两个原色的位置在整个Layer的前端,第二个黑色原色在0.25的位置:

 

而结束位置toValue,将白色和第二个黑色原色位置设置在整个Layer的末端,个黑色原色在0.75的位置:

 

从图中可以看出,此时整个Layer都变成了黑色。也就是说,在整个动画中,个黑色原色从0移动到0.75的位置,白色原色从0移动到1的位置,第二个黑色原色从0.25移动到1的位置。然后设置动画时间为2.5秒,无线重复次数,后将gradient动画添加到gradientLayer中。我们在viewDidAppear()方法中调用该动画方法gradientAnimate(),编译运行看看效果:

 

动画效果还不赖,但是如何将颜色渐变的动画作用在UILabel的文字上呢?其实非常简单,就是让UILabel上的文字称为CAGradientLayer的遮罩即可,我们先在ViewController中定义一个常量:


[cpp] view plaincopy

  1. var text = "DevTalking"  


然后在viewDidAppear()中的gradientAnimate()方法之前添加如下代码:


[cpp] view plaincopy

  1. textLabel.text = text  

  2. gradientLayer.mask = textLabel.layer  


我们再编译运行代码看看效果:

 

到目前为止,锁屏中滑动来解锁的动画效果就完成了,这个动画效果在Facebook的Paper应用中也有使用。下一节,我们在该动画的基础上对文字再加点小动画。

Text Animation

首先我们打开AppDelegate.swift,在import UIKit下面添加一个方法:


[cpp] view plaincopy

  1. func delay(seconds seconds: Double, completion:()->()) {  

  2.     let intervalTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * seconds ))  

  3.       

  4.     dispatch_after(intervalTime, dispatch_get_main_queue(), {  

  5.         completion()  

  6.     })  

  7. }  


这个方法的作用如其名称一样,是一个延迟方法,该方法的个参数是想要延迟的时间,第二个参数是一个闭包,也就是延迟的主体。这个方法用到了GCD的知识,dispatch_time主要是用于创建一个类型为dispatch_time_t的相对时间,它的个参数指的是起始时间,一般都是用预定义的DISPATCH_TIME_NOW作为个参数的值,代表当前的时间。第二个参数代表时间间隔,注意这个参数需要的时间单位是纳秒,所以我们使用预定义的NSEC_PER_SEC纳秒单位乘以希望间隔的秒数。

dispatch_after用于在队列中定时执行任务,当你想在一段时间后执行一个任务,那么就可以用这个函数。该函数的个参数指定延迟的时间,第二个参数指定一个队列,用于添加任务,第三个参数是一个闭包,也就是要执行的任务。

然后回到ViewController.swift,添加如下方法:


[cpp] view plaincopy

  1. func textAnimate(text: String) {  

  2.     if text.characters.count > 0 {  

  3.         textLabel.text = "\(textLabel.text!)\(text.substringToIndex(text.startIndex.successor()))"  

  4.         delay(seconds: 0.4, completion: {  

  5.             self.textAnimate(text.substringFromIndex(text.startIndex.successor()))  

  6.         })  

  7.     }  

  8. }  


该方法的参数text就是UILabel中要显示的文字内容。substringToIndex(_ to: Int)方法的作用是从字符串的开头一直截取到指定的位置,但不包括该指定位置的字符。text.startIndex.successor()这句意思是从text的起始位置开始取后面的一个字符。substringFromIndex(_ from: Int)方法的作用是以指定位置并包括指定位置的字符开始,一直截取之后的全部字符。所以整个方法的作用是每隔0.4秒显示一个字符,直到将整个字符串显示完。后在viewDidAppear()中注释掉textLabel.text = text这行代码,并在方法后调用textAnimate(text)方法。编译运行代码看看终效果:

 


本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!