如你所知,你在iOS APP
中看到的一切都是一个视图,比如button views
,table views
,slider views
,还有包含其他视图的父视图等。 但你可能不知道的是,在iOS
中每一个view
都是由一个叫layer
的类支撑的——一个具体的CALayer
层。 在本文中,你将了解什么是CALayer
,它是如何工作的。你还可以看到使用CALayers
做出的很酷效果的十个例子,如 shapes
(形状),gradients
(渐变),和particle system
(粒子系统)。 本文假定你已经熟悉iOS
应用开发和Swift
的基础知识,包括用storyboard
构建你的UI
。
Tips:如果你没有相关的知识也不要着急,很高兴的告诉你这儿有不少相关的教程和书籍,比如 Learn to Code iOS Apps with Swift 和 The iOS Apprentice
开始(Getting Started)
了解层级最简单的方法就是在实战中看他们是如何工作的,那么就让我们从头开始创建一个简单的项目来玩转层级。 做好写代码的准备了吗?OK,打开Xcode
然后按以下步骤:
- 在
menu
中选择File\\New\\Project…
- 在对话框中选择
iOS\\Application\\Single View Application
- 点击
Next
,输入CALayerPlayground
作为你的工程名,然后填写你的organization name
和identifier
- 语言选择
Swift
,然后设备选择Universal
- 不选择
Core Data
,然后点击Next
- 选择一个合适的地方存放你的项目(这里我将我的工程放在
user
目录下一个叫Source
的文件夹里),然后点击Creat
, 现在,你已经有了一个工程,那么接下来的一步就是创建一个view
- 在工程目录导航中,选择
Main.storyboard
- 在
menu
中选择View\\Assistant Editor\\Show Assistant Editor
,然后选择View\\Utilities\\Show Object Library
如果还没有显示出来的话 - 同时,选择
Editor\\Canvas\\Show Bounds Rectangles
,然后你就可以看到你将要添加视图场景的边界轮廓了 - 从你的
Object library
中拖一个view
放在你的视图控制器中,选中它,然后在Size inspector
(View\\Utilities\\Show Size Inspector
)中设置x
和y
为150
,width
和height
为300
- 保持这个
view
的选中状态,在auto layout toolbar
(bottom-right of the storyboard
)中点击Align
按钮,然后选中Horizontal Center in Container
和Vertical Center in Container
,将它们的值设为0
,点击添加这两个约束 - 点击
Pin
这个按钮,然后选择Width
和Height
,确保这两个值设置为300
,然后增加这两个约束
最后,将这个view
拖拽到你刚刚创建的ViewController.swift
中viewDidLoad()
这个方法的右上方,在弹出的窗口中,设置名称为viewForLayer
,然后Xcode
中的显示应该是这样的
Connect
创建这个
outlet
用如下的代码替换
ViewController.swift
中的内容
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var viewForLayer: UIView!
var l: CALayer {
return viewForLayer.layer
}
override func viewDidLoad() {
super.viewDidLoad()
setUpLayer()
}
func setUpLayer() {
l.backgroundColor = UIColor.blueColor().CGColor
l.borderWidth = 100.0
l.borderColor = UIColor.redColor().CGColor
l.shadowOpacity = 0.7
l.shadowRadius = 10.0
}
}
复制代码
正如我们前面说到的,在 iOS
中每一个view
都有与之相关联的layer
,你可以用yourView.layer
这个方法重新得到layer
。上面这段代码所做的第一件事情就是创建一个名为“l”
(“L”的小写
)的属性,用来访问viewForLayer
的layer
。 这段代码同时还调用了setUpLayer
这个方法来设置了layer
的一些属性,比如一个阴影、一个蓝色的背景和一个巨大的红色边框。关于setUpLayer()
你将会了解更多,但是首先,先让我们在模拟器上(我选择的是iPhone 6
)编译并运行我们的这个工程,来看看我们的自定义layer
,效果如下:
view
都是由一个
layer
支撑的,所以你可以在你的
APP
中对任意一个
view
做许多事情,具体如下
CALayer的一些基本属性(Basic CALayer Properties)
CALayer
有一些属性可以让你自定义它的外观。回想一下我们已经做的事情:
- 把它的背景色从默认的无色变成了蓝色
- 通过改变边框的宽度从默认的
0
到100
给它增加了一个边框 - 改变了它边框的颜色,从默认的黑色变成红色
- 最后,通过改变它阴影的透明度从默认的
0
(透明)到0.7
给了它一个阴影,这样阴影就显示出来了,然后你又使它的阴影的半径从默认的3
增加到了10
这些只是CALayer
的几个属性。让我们在尝试两次,在setUpLayer()
这个方法下添加如下两行:
l.contents = UIImage(named: "star")?.CGImage
l.contentsGravity = kCAGravityCenter
复制代码
CALayer
的contents
属性可以将图层的内容设置成一个image
,在这里我们将它设置成了一个名为“star
的一个图片。为了做到这些,你需要将这个图片添加到你的工程中,图片可以在 这里 下载。 编译并运行,然后花一点时间欣赏这个美丽的艺术品吧,如下图
“star”
是在中心位置的,这是因为你设置了
contentsGravity
这个属性为
kCAGravityCenter
,如果你愿意,你还可以将这个
“star”
的重心设置在顶部,右上,右,下,右,下,下左,左,左上角。(为了更好地理解,我将
contentsGravity
这个属性列表在这里展示出来,如下)
/** Layer `contentsGravity' values. **/
@available(iOS 2.0, *)
public let kCAGravityCenter: String
@available(iOS 2.0, *)
public let kCAGravityTop: String
@available(iOS 2.0, *)
public let kCAGravityBottom: String
@available(iOS 2.0, *)
public let kCAGravityLeft: String
@available(iOS 2.0, *)
public let kCAGravityRight: String
@available(iOS 2.0, *)
public let kCAGravityTopLeft: String
@available(iOS 2.0, *)
public let kCAGravityTopRight: String
@available(iOS 2.0, *)
public let kCAGravityBottomLeft: String
@available(iOS 2.0, *)
public let kCAGravityBottomRight: String
复制代码
Tips:关于
CALayer
的contents
、contentsGravity
等属性这里有一套关于Core Animation
的详细介绍,有兴趣的可以看下 iOS-Core-Animation-Advanced-Techniques(一)(共有七篇,这里只列出其中的一篇)
改变Layer的外观(Changing the Layer’s Appearance)
为了好玩一点,让我们在这个layer
上添加一些手势来操纵它的外观,在Xcode
中,拖拽一个单击手势(tap gesture recognizer
)在viewForLayer
这个对象上。作为参考,添加手势应该像下面这样,
Tips:如果你对手势这方面的知识不熟悉,可以看看 Using UIGestureRecognizer with Swift
用同样的方法再在viewForLayer
上添加一个捏合手势(pinch gesture recognizer
)。 然后按住control
键将每个手势从storyboard
连接到ViewController.swift
上。然后依次把他们放在setUpLayer()
和本类的右大括号之间。 在弹出视图中,将connection
切换到Action
这个选项,然后将单击手势(tap gesture recognizer
)命名为tapGestureRecognized
,将捏合手势(pinch gesture recognizer
)命名为pinchGestureRecognized
。如例:
tapGestureRecognized(_:)
这个方法改成下面这样:
@IBAction func tapGestureRecognized(sender: UITapGestureRecognizer) {
l.shadowOpacity = l.shadowOpacity == 0.7 ? 0.0 : 0.7
}
复制代码
上面这段代码的意思就是当点击viewForLayer
的时候,它的layer
的阴影的透明度(shadow opacity
)在0.7
-0
之间变化。 当然,如你所说,你也可以通过重写CALayer
的hitTest(_:)
方法来做相同的事情。事实上你也可以在本文的最后看到这种方法。 现在改变pinchGestureRecognized(_:)
方法如下:
@IBAction func pinchGestureRecognized(sender: UIPinchGestureRecognizer) {
let offset: CGFloat = sender.scale < 1 ? 5.0 : -5.0
let oldFrame = l.frame
let oldOrigin = oldFrame.origin
let newOrigin = CGPoint(x: oldOrigin.x + offset, y: oldOrigin.y + offset)
let newSize = CGSize(width: oldFrame.width + (offset * -2.0), height: oldFrame.height + (offset * -2.0))
let newFrame = CGRect(origin: newOrigin, size: newSize)
if newFrame.width >= 100.0 && newFrame.width <= 300.0 {
l.borderWidth -= offset
l.cornerRadius += (offset / 2.0)
l.frame = newFrame
}
}
复制代码
在这里基于用户的捏合手势可以创建一个正的或者负的偏移量来改变layer
的大小(frame
)、边框的宽度(width
)和边框的圆角半径(corner radius
)。 每一个layer
默认的圆角半径(corner radius
)是0
,这就意味着如果layer
有一个90°
的角,那么他就是一个标准的矩形。圆角将会随着半径的增大而产生。那么如何将一个方形的layer
变成一个圆形的呢?很简单,就是把它的圆角半径(corner radius
)设为宽度的一半。 需要注意的是调整圆角半径并不会裁剪layer
的contents
(“star”
这个图),除非你将layer
的masksToBounds
属性设置为true
。 编译并且运行,试着点击和捏合这个view
:
CALayer的伟大之旅(The Great CALayer Tour)
当然,
CALayer
还有更多的属性和方法用来操作,比如它的有些子类,拥有一些特别的属性和方法。 除了本文以外,你将会需要下面的这些:
- [The Layer Player App](https://itunes.apple.com/us/app/layer-player/id949768742?mt=8)
- [The Layer Player Source Code](https://github.com/scotteg/LayerPlayer)
这是一个很方便的app包含了本文中的所有10个例子,下面是这十个例子的预览:
当我们在阅读下面每个例子的时候,我建议大家都运行一下这个app,然后有选择的看看所提供的源代码。其实你并不需要对本文的余下部分编写代码,所有的代码都已经提供,所以,坐下来,轻松地阅读吧! 这些对你来说应该是一些很好的例子当你需要添加一些CALayers
的一些类到自己公程中的时候,我们希望你能喜欢!
例一: CALayer
在上面我们已经看到过一个使用CALayer
的例子,并且设置了一些属性。然而还有一些关于CALayer
的属性,在上面并没有提到:
- **
Layers can have sublayers.
** 就像view
可以拥有子view
一样,layer
可以拥有子layer
,利用这个特点你可以做出一些特殊的效果。 - **
Layer properties are animated.
**当你改变一个layer
的属性的时候,它默认的属性就会随着时间变化。当然你也可以根据时间自定义这些动画。 Layers are lightweight.
Layers
是比Views
更加轻量的,因此使用Layer
会帮助你获得更好地性能。Layers have tons of useful properties.
Layer
有很多有用的属性。上面我们已经见过几个,下面让我们看看更多! 就像你之前所看到的,Layer
有很多实用的属性,那么就让我们来看看CALayer
的完整的属性列表--一些你之前没有见过的但是很实用的!
// 1
let layer = CALayer()
layer.frame = someView.bounds
// 2
layer.contents = UIImage(named: "star")?.CGImage
layer.contentsGravity = kCAGravityCenter
// 3
layer.magnificationFilter = kCAFilterLinear
layer.geometryFlipped = false
// 4
layer.backgroundColor = UIColor(red: 11/255.0, green: 86/255.0, blue: 14/255.0, alpha: 1.0).CGColor
layer.opacity = 1.0
layer.hidden = false
layer.masksToBounds = false
// 5
layer.cornerRadius = 100.0
layer.borderWidth = 12.0
layer.borderColor = UIColor.whiteColor().CGColor
// 6
layer.shadowOpacity = 0.75
layer.shadowOffset = CGSize(width: 0, height: 3)
layer.shadowRadius = 3.0
someView.layer.addSublayer(layer)
复制代码
在上面的代码中:
- 1.创建了一个
CALayer
的实例然后让它的大小等于someView
的大小。 - 2.将
layer
的contents
属性设置一个image
,并且把这个image
放在这个layer
的中心。需要注意的是这里需要使用的是CGImage
。 - 3.通过
contentsGravity
来放大图像的时候选择用kCAFilterLinear
,这个属性可以调整大小(形状、尺寸)和位置(上、下、左、右)。在之前的变化中并没有做动画,但是如果geometryFlipped
没有设置为true
,它阴影的几何位置将会颠倒,继续: - 4.我们设置了它的背景色(
r/g/b
)和透明度(透明度为1
),与此同时我们设置了masksToBounds
为false
,这意味着如果它的大小小于其contents
(例子中的star
图片),图像就不会裁剪。 - 5.我们设置了
layer
的圆角半径为宽度的一半,并设置了一个宽度为12
的圆形边界效果,需要注意的是这里设置颜色需要用CGColor
- 6.创建一个阴影并且设置
shouldRasterize
为true
(下面会讲到),然后添加到view
的层级中
结果如下:
CALayer
还有有两个可以提高性能的附加属性:
shouldRasterize
和
drawsAsynchronously
。
shouldRasterize
这个属性默认的是false
,但是当你把它设置成true
的时候就会提升性能,因为这个设置使图层的内容只呈现一次。它非常适合那些在屏幕上做动画,但是不需要改变外形的对象。drawsAsynchronously
这个属性几乎是与shouldRasterize
相反的。它的默认值也是false
,当一个Layer
的内容需要反复重画的时候把它设置成true
将会提升性能,比如说使用粒子发射器(具体请见后面CAEmitterLayer
这个例子)。
注意:考虑到给一个指定的
Layer
的shouldRasterize
和drawsAsynchronously
这两个属性设置为true
,排除其他影响,比较true
和false
之后你会发现设置为true
之后性能的确提升了,但是注意请不要误用,否则性能会急速下降,效果适得其反!
现在,让我们简短的把注意力集中在这个Layer Player
上,它能控制操纵layer
的许多属性:
试玩一下里面的各种控制——这将会是你对CALayer
的功能理解的最有效地方式!
注意:图层并不是响应链的一部分,所以它不会像
view
那样直接响应触摸或者手势,就像你在CALayerPlayground
这个例子中看到的一样。 但是,你可以对它们进行hit test
,同样你可以在CATransformLayer
里面看见相关的代码。当然你也可以对Layer
添加一些自定义的动画,在后面的CAReplicatorLayer
里面我们同样会看到!
例二: CAScrollLayer
CAScrollLayer
显示的是滚动层的一部分,它使非常基础的,不能直接的响应用户的触摸,所以它可以在它的滚动范围内做很多炫酷的事情! UIScrollView
并不能直接使用CAScrollLayer
来做这些事情,它是直接通过改变layer
的bounds
来做的。对于CAScrollLayer
,你需要做的就是设置它的滚动方向(水平或者竖直),同时你可以动态的设置他滚动到一个point
或者rect
。
// In ScrollingView.swift
import UIKit
class ScrollingView: UIView {
// 1
override class func layerClass() -> AnyClass {
return CAScrollLayer.self
}
}
// In CAScrollLayerViewController.swift
import UIKit
class CAScrollLayerViewController: UIViewController {
@IBOutlet weak var scrollingView: ScrollingView!
// 2
var scrollingViewLayer: CAScrollLayer {
return scrollingView.layer as CAScrollLayer
}
override func viewDidLoad() {
super.viewDidLoad()
// 3
scrollingViewLayer.scrollMode = kCAScrollBoth
}
@IBAction func tapRecognized(sender: UITapGestureRecognizer) {
// 4
var newPoint = CGPoint(x: 250, y: 250)
UIView.animateWithDuration(0.3, delay: 0, options: .CurveEaseInOut, animations: {
[unowned self] in
self.scrollingViewLayer.scrollToPoint(newPoint)
}, completion: nil)
}
}
复制代码
上面所有的代码里面:
- 1、重写了
layerClass()
这个方法,返回一个CAScrollLayer
,这是快速创建一个新的layer
的一种方式,就像在CALayer
这个例子中一样。 - 2、定义了
scrollingViewLayer
- 3、设置了可以在水平和竖直两个方向上滑动
- 4、当点击手势被识别的时候,就会创建一个新的点,
scrolling layer
就会以动画的形式滑动到这一点。需要注意的是:scrollToPoint(_:)
和scrollToRect(_:)
这两个方法并不会自动做动画
例子分析:一个ScrollingView
包含了一个比他自身还要大的imageView
,当你运行所有的代码并且点击上面的view
时,效果如下图:
本例子中,包含控制水平和竖直方向滑动的控件 下面有一些当你使用(或者不使用)CAScrollLayer
的一些经验:
- 如果你需要的是轻量的,并且只能用编程的方式滑动,那么你就可以考虑使用
CAScrollLayer
- 如果你只是使用户可以滑动,那么你选择
UIScrollView
会更好。如果想了解更多,可以查看我们的 18部视频教学 - 如果你要滑动一个非常大的图像,建议使用
CATiledLayer
(详见下文)
例三: CATextLayer
CATextLayer
给纯文本和attributed strings
提供了简单而又快速的渲染方法。与UILabel
不同的是,CATextLayer
中不能使用UIFont
,只能是CTFontRef
或者CGFontRef
。 就像下面的代码块中,CATextLayer
可以控制font
,font size
,color
,alignment
,wrapping
,truncation
等属性,还有就是动画,代码如下:
// 1
let textLayer = CATextLayer()
textLayer.frame = someView.bounds
// 2
var string = ""
for _ in 1...20 {
string += "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce auctor arcu quis velit congue dictum. "
}
textLayer.string = string
// 3
let fontName: CFStringRef = "Noteworthy-Light"
textLayer.font = CTFontCreateWithName(fontName, fontSize, nil)
// 4
textLayer.foregroundColor = UIColor.darkGrayColor().CGColor
textLayer.wrapped = true
textLayer.alignmentMode = kCAAlignmentLeft
textLayer.contentsScale = UIScreen.mainScreen().scale
someView.layer.addSublayer(textLayer)
复制代码
上述代码的解释:
- 1、创建了一个
CATextLayer
的实例,并设置了大小为someView
的大小 - 2、创建了一个文本,并将
textLayer.string
设置为string
- 3、创建了一个
font
为Noteworthy-Light
,并将textLayer.font
设置为了这个font
- 4、设置
layer
的wrapped
和alignmentMode
(你可以设置左对齐、右对齐和中间对齐),然后设置它的缩放比例跟屏幕的缩放比例一致,然后加在someView
的layer
上
所有的层类,并不仅仅是CATextLayer
,都是以1:1
呈现给我们的。当附属于某一个view
的时候,layer
默认以当前view
的比例因子呈现在屏幕上,你需要给你自己创建的层级设置一个明确的比例因子,否则它的比例因子会默认的被设置为1
如果将它放在一个方方正正的视图上,那么将会向下面这样显示:
Truncation
这个属性你可以自己设置看看效果,当你想用省略号截断文本,用这个属性是一个不错的方法。
Truncation
默认的是
none
,但是可以设置
start
、
end
、
middle
这三种方式。
在
demo
中你可以控制改变
CATextLayer
的很多属性,如下:
例四: AVPlayerLayer
AVPlayerLayer
给AVFoundation
带来了不少方便之处,它拥有AVPlayer
去播放一个媒体影音文件(AVPlayerItems
)。下面是一个创建AVPlayerLayer
的例子:
override func viewDidLoad() {
super.viewDidLoad()
// 1
let playerLayer = AVPlayerLayer()
playerLayer.frame = someView.bounds
// 2
let url = NSBundle.mainBundle().URLForResource("someVideo", withExtension: "m4v")
let player = AVPlayer(URL: url)
// 3
player.actionAtItemEnd = .None
playerLayer.player = player
someView.layer.addSublayer(playerLayer)
// 4
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerDidReachEndNotificationHandler:", name: "AVPlayerItemDidPlayToEndTimeNotification", object: player.currentItem)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
// 5
@IBAction func playButtonTapped(sender: UIButton) {
if playButton.titleLabel?.text == "Play" {
player.play()
playButton.setTitle("Pause", forState: .Normal)
} else {
player.pause()
playButton.setTitle("Play", forState: .Normal)
}
updatePlayButtonTitle()
updateRateSegmentedControl()
}
// 6
func playerDidReachEndNotificationHandler(notification: NSNotification) {
let playerItem = notification.object as AVPlayerItem
playerItem.seekToTime(kCMTimeZero)
}
复制代码
我们来分析一下上面的代码:
- 1、创建了一个新的
layer
,并设置了它的frame
- 2、创建了一个
AVPlayer
的对象 - 3、设置当
plyer
播放完毕以后什么事情也不做,包括播放或者切换下一项(如果有的话) - 4、当
AVPlayer
播放完成以后为它注册一个通知(并设置当这个消息处理结束以后在deinit
里面移除掉观察者) - 5、设置当按钮点击的时候就出发视频播放的开关和设置按钮的
title
请注意,这只是一个供你开始AVPlayerLayer
的简单例子,在实际的项目中,通过button
的title
来判断播放状态这种方法通常是不可取的。 上面AVPlayerLayer
和AVPlayer
所创建的将会在视觉上实现AVPlayerItem
的第一帧,如下:
AVPlayerLayer
有几个附加的属性:
videoGravity
这个属性用来调整视频的显示尺寸readyForDisplay
这个属性用来检查视频是否准备播放
另一方面,AVPlayer
有相当多的属性和方法。有一点需要注意的就是速度,比如播放的速率就是从 0 到 1 。0 的意思就是暂停,1 的意思是视频播放的速度是正常的速度(1x)。 然而,设置播放速率也可以控制播放暂停。换句话说,如果想设置暂停的话,就把播放速率设置为 0 。同理,想设置播放的话,就可以把速率设置为 1 。 那么你可能会问,关于快放、慢放和快退是怎么样的体现呢?对于以上这些,AVPlayerLayer
都有包含,设置高于一倍的速率就意味着咦当前倍率播放,比如你设置了速率为 2 意味着,播放速度为两倍于当前速率。 正如你可能会认为的那样,速度设置为负数的时候,视频将会以这个速率快退。 当你设置以比正常速率快或者慢播放的之前(向前),然而,AVPlayerItem
这个例子中已经提供了适当的方法以验证各种速率:
canPlayFastForward()
高于 1 的速率canPlaySlowForward()
0 ~ 1 的速率canPlayReverse()
速率为 -1canPlaySlowReverse()
速率为 -1 ~ 0canPlayFastReverse()
低于 -1 的速率
大多数视频可以通过不同的速率向前播放,但是很少有可以反向播放的。AVPlayerLayer
提供了反向播放的功能:
例五: CAGradientLayer
CAGradientLayer
便于两个或多个颜色交融在一起,因而特别适合于背景。你需要指定一个颜色的数组来配置它,此外还需要一个startPoint
和一个endPoint
来指定CAGradientLayer
的开始和结束。 但是请注意,startPoint
和一个endPoint
并不是一个明确的点。相反,它们是定义在空间坐标系中,然后绘制的时候直接映射到Layer
层中。换句话说,x 的坐标为 1 的意思就是该点在Layer
的右边缘,当 Y 为 1 的时候意味着该点在layer
的底部边缘。 CAGradientLayer
有一个type
属性,虽然只有kCAGradientLayerAxial
这一个选项,但是它可以线性的过度数组中的每一个颜色。 这就意味着,如果你在startPoint
和endPoint
之间画一条直线 A ,颜色将会沿着直线 B (假想出来的,垂直于 A )渐变,并且在 B 上所有点的颜色都相同。
CAGradientLayer
的停止位置,那么它将会默认平均分布,如果分配各个颜色的位置,设置位置的时候必须和颜色的数组相匹配,否则会有不好的事情发生。 下面有一个
CAGradientLayer
的例子:
let gradientLayer = CAGradientLayer()
gradientLayer.frame = someView.bounds
gradientLayer.colors = [cgColorForRed(209.0, green: 0.0, blue: 0.0),
cgColorForRed(255.0, green: 102.0, blue: 34.0),
cgColorForRed(255.0, green: 218.0, blue: 33.0),
cgColorForRed(51.0, green: 221.0, blue: 0.0),
cgColorForRed(17.0, green: 51.0, blue: 204.0),
cgColorForRed(34.0, green: 0.0, blue: 102.0),
cgColorForRed(51.0, green: 0.0, blue: 68.0)]
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0, y: 1)
someView.layer.addSublayer(gradientLayer)
func cgColorForRed(red: CGFloat, green: CGFloat, blue: CGFloat) -> AnyObject {
return UIColor(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: 1.0).CGColor as AnyObject
}
复制代码
在上面的代码中,创建了一个CAGradientLayer
,设置它的frame
和someView
的大小一致,指定颜色数组,设置startPoint
和endPoint
,并将gradient layer
添加到图层中。效果看起来应该如下:
demo
中你可以控制
startPoint
和
endPoint
、颜色和位置,如下:
例六: CAReplicatorLayer
CAReplicatorLayer
是按一个指定的数复用一个层组成的,这样在复用的时候就可以做出很多酷炫的效果了。 每个复用的layer
都可以有不同的颜色和位置, 如果设置了延迟绘图会使整个layer
层的动画延迟。preservesDepth
这个属性设置会实现3D
或者2D
效果,如下:
// 1
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.frame = someView.bounds
// 2
replicatorLayer.instanceCount = 30
replicatorLayer.instanceDelay = CFTimeInterval(1 / 30.0)
replicatorLayer.preservesDepth = false
replicatorLayer.instanceColor = UIColor.whiteColor().CGColor
// 3
replicatorLayer.instanceRedOffset = 0.0
replicatorLayer.instanceGreenOffset = -0.5
replicatorLayer.instanceBlueOffset = -0.5
replicatorLayer.instanceAlphaOffset = 0.0
// 4
let angle = Float(M_PI * 2.0) / 30
replicatorLayer.instanceTransform = CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0)
someView.layer.addSublayer(replicatorLayer)
// 5
let instanceLayer = CALayer()
let layerWidth: CGFloat = 10.0
let midX = CGRectGetMidX(someView.bounds) - layerWidth / 2.0
instanceLayer.frame = CGRect(x: midX, y: 0.0, width: layerWidth, height: layerWidth * 3.0)
instanceLayer.backgroundColor = UIColor.whiteColor().CGColor
replicatorLayer.addSublayer(instanceLayer)
// 6
let fadeAnimation = CABasicAnimation(keyPath: "opacity")
fadeAnimation.fromValue = 1.0
fadeAnimation.toValue = 0.0
fadeAnimation.duration = 1
fadeAnimation.repeatCount = Float(Int.max)
// 7
instanceLayer.opacity = 0.0
instanceLayer.addAnimation(fadeAnimation, forKey: "FadeAnimation")
复制代码
如上的所有代码中:
- 1.创建了一个
CAReplicatorLayer
的实例,并设置它的frame
为someView
的大小 - 2.设置
CAReplicatorLayer
的复用层数(instanceCount
)和延迟绘制的时间。同时还设置了复用层为2D
(preservesDepth = false
),颜色为白色。 - 3.为每个实例增加
r/g/b
色值,在没有设置的情况下,默认的都是0
,并且保留在整个实例中。然而,在这种情况下,这个实例的最初始颜色就被设置成白色了,意味着红绿蓝三种颜色都被设置成 1 了.