10月14日-16日,由CSDN和创新工场联合主办的 MDCC 2015中国移动开发者大会 将在北京新云南皇冠假日酒店隆重召开,现在抢注大会门票,即享多重好礼!
在很多人的心目中iPhone的经典机型应该是iPhone4,精湛的工艺、完美的屏幕配上暗色的锁屏壁纸,看着屏幕底部闪烁的 slide to unlock 字样,高逼格彰显无遗。时至今日无论iPhone机身样式如何改变,屏幕尺寸如何改变,iOS系统如何改变,唯有锁屏底部闪烁的 滑动来解锁 不变。它的动画效果是如何实现的呢,这篇文章会告诉你们答案。
新建一个应用名为 GradientAnimation ,打开 Main.storyboard
,将ViewController的View背景色设置为灰黑色,拖一个UIView到ViewController中,将其颜色设置为无色并设置好布局约束:
接着我们拖一个UILabel到刚才拖入的UIView中,设置高宽等同于它的父视图:
我对该UILabel的属性设置如下:
之后,我们在 ViewController
中添加UIView和UILabel的Outlet:
接下来回到 ViewController.swift
,我们添加一个常量属性 gradientLayer
:
let gradientLayer = CAGradientLayer()
这里出现了CALayer的另一个子类CAGradientLayer,这个类的作用就是能在Layer上绘制出渐变颜色的效果,然后在 viewDidLoad()
中添加如下代码:
gradientLayer.bounds = CGRect(x: 0, y: 0, width: backgroundView.frame.size.width, height: backgroundView.frame.size.height) gradientLayer.position = CGPoint(x: backgroundView.frame.size.width/2, y: backgroundView.frame.size.height/2)
上述两行的代码是设置Layer的大小及位置,这在上两篇文章中已经讲过,这里就不再累赘了。接着我们继续添加两行代码:
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5) gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
既然CAGradientLayer可以绘制出渐变颜色的效果,那自然有颜色渐变的方向,所以这两行代码的作用就是设置颜色渐变的起始点和结束点,这两个属性共同决定了颜色渐变的方向:
从上面的示意图中可以看出,CAGradientLayer是通过起始点和结束点的坐标位置来决定颜色渐变的方向的,起始点的默认值是(0.5, 0),结束点的默认值是(0.5, 1),也就是说默认的颜色渐变方向是沿垂直中线从上往下渐变的,我们在这里将它改成了沿水平中线从左往右渐变。
接下来我们设置CAGradientLayer的渐变颜色,接着添加如下代码:
gradientLayer.colors = [ UIColor.blackColor().CGColor, UIColor.whiteColor().CGColor, UIColor.blackColor().CGColor ]
CAGradientLayer的 colors
属性类型是一个数组 [AnyObject]
,这就意味着我们可以实现多个颜色的渐变效果,并且可以规定各个颜色的顺序。不过在我们这个示例中我们只需要两种颜色,不过需要注意的是虽然颜色只有两种,但是整个颜色渐变的过程中有三个原色点,那就是黑、白、黑,所以我们在这个数组中也需要按照原色点的数量和顺序添加相应的颜色,哪怕颜色都是一样的。
我们既然设置了渐变的三个原色,那么就要对这原色出现的位置进行设置,接着添加如下代码:
gradientLayer.locations = [0.2, 0.5, 0.8]
从上述代码中不难看出,我们将第一个黑色原色出现的位置设置在了整个Layer长度的十分之二的位置,第二个白色原色在中间,第三个黑色原色在十分之八的位置:
设置完CAGradientLayer的相关属性后,我们将 gradientLayer
添加到 backgroundView
的Layer中:
backgroundView.layer.addSublayer(gradientLayer)
现在我们编译运行一下代码看看效果:
接下来我们需要让颜色渐变动起来,先创建一个方法 gradinetAnimate()
,在方法中添加如下代码:
let gradient = CABasicAnimation(keyPath: "locations") gradient.fromValue = [0, 0, 0.25] gradient.toValue = [0.75, 1, 1] gradient.duration = 2.5 gradient.repeatCount = HUGE 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
中定义一个常量:
var text = "DevTalking"
然后在 viewDidAppear()
中的 gradientAnimate()
方法之前添加如下代码:
textLabel.text = text gradientLayer.mask = textLabel.layer
我们再编译运行代码看看效果:
到目前为止,锁屏中 滑动来解锁 的动画效果就完成了,这个动画效果在Facebook的Paper应用中也有使用。下一节,我们在该动画的基础上对文字再加点小动画。
首先我们打开 AppDelegate.swift
,在 import UIKit
下面添加一个方法:
func delay(seconds seconds: Double, completion:()->()) { let intervalTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * seconds )) dispatch_after(intervalTime, dispatch_get_main_queue(), { completion() }) }
这个方法的作用如其名称一样,是一个延迟方法,该方法的第一个参数是想要延迟的时间,第二个参数是一个闭包,也就是延迟的主体。这个方法用到了GCD的知识, dispatch_time
主要是用于创建一个类型为 dispatch_time_t
的相对时间,它的第一个参数指的是起始时间,一般都是用预定义的 DISPATCH_TIME_NOW
作为第一个参数的值,代表当前的时间。第二个参数代表时间间隔,注意这个参数需要的时间单位是纳秒,所以我们使用预定义的 NSEC_PER_SEC
纳秒单位乘以希望间隔的秒数。
dispatch_after
用于在队列中定时执行任务,当你想在一段时间后执行一个任务,那么就可以用这个函数。该函数的第一个参数指定延迟的时间,第二个参数指定一个队列,用于添加任务,第三个参数是一个闭包,也就是要执行的任务。
然后回到 ViewController.swift
,添加如下方法:
func textAnimate(text: String) { if text.characters.count > 0 { textLabel.text = "/(textLabel.text!)/(text.substringToIndex(text.startIndex.successor()))" delay(seconds: 0.4, completion: { self.textAnimate(text.substringFromIndex(text.startIndex.successor())) }) } }
该方法的参数 text
就是UILabel中要显示的文字内容。 substringToIndex(_ to: Int)
方法的作用是从字符串的开头一直截取到指定的位置,但不包括该指定位置的字符。 text.startIndex.successor()
这句意思是从 text
的起始位置开始取后面的一个字符。 substringFromIndex(_ from: Int)
方法的作用是以指定位置并包括指定位置的字符开始,一直截取之后的全部字符。所以整个方法的作用是每隔0.4秒显示一个字符,直到将整个字符串显示完。最后在 viewDidAppear()
中注释掉 textLabel.text = text
这行代码,并在方法最后调用 textAnimate(text)
方法。编译运行代码看看最终效果:
系列阅读:
CALayer动画实践(二):CAReplicatorLayer的用法
CALayer Animation实践(一):让应用灵动起来!
作者简介:
付宇轩(@DevTalking),从事Java中间件开发、iOS开发。主要主持开发企业级ETL中间件、BPM中间件、企业级移动应用,个人博客地址: http://www.devtalking.com 。
预告: 2015中国移动开发者大会(MDCC 2015) 将于10月14日-16日在北京新云南皇冠假日酒店召开。大会特设九大技术专场:平台与技术(iOS)、平台与技术(Android)、平台与技术(跨平台)、产品与设计、游戏开发、企业移动化、虚拟现实专场、硬件开发与技术、嵌入式开发。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。