本文淘汰.最新文章http://m.itdecent.cn/p/b64136e6fc79
我這篇譯文為完全翻譯,原作者的10個(gè)例子我都翻完了.
CALayer Tutorial: Getting Started
大家都清楚,iOS應(yīng)用里能看到的東西都是view,而實(shí)際上view的顯示功能是由另一個(gè)類CALayer來實(shí)現(xiàn)的.這篇文章講了10個(gè)展示CALyer酷炫效果的例子.學(xué)習(xí)這個(gè)教程的前提是你有iOS開發(fā)的基礎(chǔ)能力,懂swift,用storyboard布置UI.
Getting Started
最快明白layer的方法就是實(shí)戰(zhàn).廢話不多說,我們建個(gè)項(xiàng)目玩一玩layer.
1.啟動(dòng)Xcode(廢話)
2.菜單里選擇 File\New\Project….如果是剛啟動(dòng)出現(xiàn)在開始界面的話就選擇新建一個(gè)新項(xiàng)目
3.在對(duì)話欄選擇 iOS\Application\Single View Application
4.點(diǎn)next,在Product Name輸入"CALayerPlayground",organization name 和 identifier 隨你來
5.Language選擇swift,Devices選Universal
6.保證Core Data的勾沒有被打上,選next
7.選個(gè)你喜歡的路徑放你的項(xiàng)目,然后creat
好,項(xiàng)目創(chuàng)建OK了,接下來要有view
8.在項(xiàng)目導(dǎo)航器里選Main.storyboard
9.把Object Library和Assistant Editor顯示出來,如果已經(jīng)顯示了就跳過這一步
10.選擇Editor\Canvas\Show Bounds Rectangles,好讓你看到view的邊框線
11.從Object Library拖一個(gè)view到viewcontroller的scene里,把x和y設(shè)為150,寬高設(shè)為300
12.選中這個(gè)view,給這個(gè)view添加Horizontal Center in Container 和 Vertical Center in Container這兩個(gè)約束,在Xcode底部的align按鈕里操作.
13.同樣點(diǎn)擊底部的pin按鈕,把寬高設(shè)為300
14.最后通過control加拖view的方式把view連接到ViewController.swift文件中,outlet起名為viewForlayer
好了,Xcode現(xiàn)在應(yīng)該是醬紫的

ViewController.swift文件中的內(nèi)容替換為如下內(nèi)容
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
}
}
前面說的每個(gè)view都有一個(gè)layer,你能用yourView.layer來訪問layer.這段代碼做的第一件事就是創(chuàng)建了一個(gè)可以用來訪問viewForLayer的layer的屬性,這個(gè)屬性名稱是小寫l,緊接著的代碼就用到了這個(gè)屬性的內(nèi)容.
這段代碼還調(diào)用了setUpLayer方法來設(shè)置layer的幾個(gè)屬性,比如陰影,背景色,還有線框色.等下你就會(huì)明白setUpLayer()方法.不過現(xiàn)在還是運(yùn)行一下程序來看看你的自定義layer.
[圖片上傳失敗...(image-8d1b48-1587374045880)]
才幾行代碼就有折么酷炫的效果.每一個(gè)view都可以做這樣的事,只要它有l(wèi)ayer.接下來仔細(xì)看看.
CALayer的基礎(chǔ)屬性
CALayer有幾個(gè)可以改變它外觀的屬性,回想一下你做過哪些
1.把layer的背景色從默認(rèn)的沒有顏色改成藍(lán)的
2.把它的線寬從默認(rèn)的0改成了100
3.把它的顏色從黑色改成了紅色
4.最后還是改了陰影,把不透明度從默認(rèn)的0改到了0.7,這樣就顯示了陰影.然后又把陰影半徑從默認(rèn)的3改到了10.
你能設(shè)置CALayer的幾個(gè)屬性.來,多試兩個(gè).把下面兩行代碼加到setUpLayer()方法的底部:
l.contents = UIImage(named: "star")?.CGImage
l.contentsGravity = kCAGravityCenter
content屬性能讓你給layer的內(nèi)容物設(shè)置一張圖片,所以你是放了一張名稱是star的圖片在這里.當(dāng)然,首先你得把圖片放到項(xiàng)目里.[圖片上傳失敗...(image-a05a0c-1587374045880)]
把它放到項(xiàng)目,運(yùn)行看一下效果
[圖片上傳失敗...(image-1e6b7a-1587374045880)]
看看圖片為什么是居中的,因?yàn)榘裞ontentsGravity屬性設(shè)置為kCAGravityCenter了.你沒想錯(cuò),你也可以設(shè)為居上下左右,左上左下等等.
改變Layer的外觀
我們來玩一下,加幾個(gè)手勢(shì)識(shí)別器來控制layer的外觀.在Xcode里,拖一個(gè)點(diǎn)擊手勢(shì)識(shí)別器到viewForLayer對(duì)象上.參考一下,下面的圖片是拖手勢(shì)識(shí)別器到對(duì)象上看起來的樣子:
[圖片上傳失敗...(image-e60a52-1587374045880)]
提示:如果對(duì)手勢(shì)識(shí)別器不熟悉,可以看下這篇文章Using UIGestureRecognizer with Swift.
重復(fù)上面的步驟,再加一個(gè)縮放手勢(shì).
通過control加拖拽的方式把storyboard頂部的兩個(gè)手勢(shì)識(shí)別器拖到ViewController.swift里去,把它們加到setUpLayer()方法下面.
[圖片上傳失敗...(image-d92efa-1587374045880)]
把tapGestureRecognized(_:)改成這樣:
@IBAction func tapGestureRecognized(sender:
UITapGestureRecognizer) {
l.shadowOpacity = l.shadowOpacity == 0.7 ? 0.0 : 0.7
}
這段代碼的意思是讓layer根據(jù)點(diǎn)擊手勢(shì)來讓它的不透明度在0和0.7之間變動(dòng).
當(dāng)然你也可以重寫hitTest(_:)方法達(dá)到同樣的效果,等下我們就會(huì)用到這個(gè)方法.我們來理解一下上面方法的邏輯,layer能做的只有hit testing,它與手勢(shì)識(shí)別互動(dòng)不了.所以我們是把手勢(shì)識(shí)別器加到view上面.
現(xiàn)在來把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 }
}
這段代碼根據(jù)縮放手勢(shì)來生成正的或者負(fù)的位移,調(diào)整layer的frame,邊線的寬度和圓角.
layer的圓角默認(rèn)都是0,也就是個(gè)矩形.增加圓角值能生成圓角,當(dāng)圓角值是layer寬度的一半就會(huì)變成一個(gè)圓了.
設(shè)置圓角不會(huì)剪切l(wèi)ayer的內(nèi)容,只有把masksToBounds設(shè)為true才會(huì)剪切.
運(yùn)行看一下吧:
[圖片上傳失敗...(image-108568-1587374045880)]
The Great CALayer Tour
[圖片上傳失敗...(image-6090d9-1587374045880)]
CALayer不是只有你想的幾個(gè)屬性和方法,它還有幾個(gè)擁有獨(dú)一無二的屬性和方法的子類.
有比guided tour更好的了解這些API的途徑嗎,raywenderlich.com-style?
對(duì)于接下來的文章,你需要兩樣?xùn)|西:
The Layer Player App
The Layer Player Source Code
這個(gè)handy app有十個(gè)不同的等下你會(huì)學(xué)習(xí)到的CALayer類型的樣例,來看看大概是神馬樣子的:
[圖片上傳失敗...(image-db9625-1587374045880)]
每當(dāng)學(xué)到下面的某個(gè)樣例,我建議你玩一下這個(gè)CALayer app,隨意地看一下我給你的源碼.不要慌,你不用把所有代碼都碼下來,放輕松慢慢看.
這些樣例應(yīng)該是很不錯(cuò)的學(xué)習(xí)不同CALayer的途徑,我們希望你能夠喜歡.
Example #1: CALayer
前面已經(jīng)講了怎樣使用CALayer類.
下面是另外幾個(gè)沒講到的屬性
****1.layer可以擁有子layer.**** 就像view可以擁有子view.你能拿來做很多酷炫效果.
****2.layer屬性是具有動(dòng)畫性的.**** 修改layer的屬性能生成隨時(shí)間變化的動(dòng)畫效果.也可以自定義動(dòng)畫的時(shí)間.
****3.layer是輕量級(jí)的.**** layer要比view輕量,因此layer能達(dá)到更高效的性能.
****4.layer有很多有用的屬性.**** 你已經(jīng)看了很多了,接下來再看看其他的吧.
前面你已經(jīng)看到了,layer有很多有用的屬性.我們來看下CALayer的所有屬性吧,有些已經(jīng)看到過.相當(dāng)便手哦!
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
layer.shouldRasterize = true
someView.layer.addSublayer(layer)
1.創(chuàng)建一個(gè)CALayer的實(shí)例,把someView的bounds設(shè)給它.
2.居中設(shè)置一張圖片給這個(gè)layer.注意.CGImage對(duì)象是assigned的.
3.使用contentsGravity會(huì)使用這個(gè)放大濾鏡,能夠改變所有的size和position.如果geometryFlipped沒有設(shè)為true,坐標(biāo)系和陰影會(huì)反轉(zhuǎn).
4.背景色設(shè)為綠色,將layer設(shè)為可見, masksToBounds設(shè)為false,也就是當(dāng)layer的size比contents得size要小時(shí),不會(huì)裁剪contents.
5.圓角值設(shè)為寬度的一半,那么視覺上就會(huì)成為一個(gè)圓.注意,layer的顏色是指定為CGColor類型的.
6.創(chuàng)建了陰影效果,把shouldRasterize開啟為true(下面會(huì)講到).(譯者注:原文代碼里并沒有l(wèi)ayer.shouldRasterize = true這句代碼,我加了進(jìn)去)
嗯,來看一下效果:
[圖片上傳失敗...(image-c5cf4a-1587374045880)]
CALayer有兩個(gè)提高性能的屬性,分別是 shouldRasterize 和 drawsAsynchronously.
shouldRasterize默認(rèn)為false.設(shè)為true能提高性能的原因是layer的contents只會(huì)被渲染一次.這個(gè)方法對(duì)于那些只是用來在屏幕上做動(dòng)畫,但是外觀不會(huì)變的對(duì)象有奇效.
drawsAsynchronously則與shouldRasterize完全相反.它默認(rèn)也是false.如果某個(gè)對(duì)象需要重復(fù)地被繪制,那么開啟true就能提高性能.比如例子發(fā)射layer,它會(huì)持續(xù)不斷地渲染動(dòng)畫性的細(xì)小的圖像(譯者:可以想象一下雨雪,火焰這樣的東西).(等下CAEmitterLayer會(huì)講到.)
提醒一句:使用這兩個(gè)屬性時(shí)想一下可能的后果.對(duì)比一下開合沒開的性能.當(dāng)沒開時(shí),性能可能低得一塌糊涂.
接下來把注意力轉(zhuǎn)移到 Layer Player.它集合了對(duì)layer屬性的很多控制:
[圖片上傳失敗...(image-1d1631-1587374045880)]
注意:在CALayerPlayground 項(xiàng)目里你了解到,layer不是響應(yīng)鏈里的一員,所以它對(duì)觸摸和手勢(shì)不能做出反應(yīng).
但是你可以CATransformLayer的樣例里看到我們可以hit test他們.在CAReplicatorLayer樣例又能看到添加自定義動(dòng)畫效果
xample #2: CAScrollLayer
CAScrollLayer顯示一個(gè)可滾動(dòng)layer的一部分.CAScrollLayer相當(dāng)?shù)幕A(chǔ),它不能對(duì)觸摸做出反應(yīng),甚至查看這個(gè)可滾動(dòng)layer的bounds,所以它只能防止?jié)L動(dòng)超出范圍.
UIScrollView并沒有使用CAScrollLayer來實(shí)現(xiàn)自己的滾動(dòng)功能,UIScrollView實(shí)際上是通過修改layer的bounds來達(dá)到滾動(dòng)效果的.
對(duì)于CAScrollLayer,你能告訴它滾動(dòng)模式是什么,垂直的或者水平的,或者讓它滾動(dòng)到某個(gè)精確的點(diǎn)或者矩形.
// 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.寫了一個(gè)UIView的子類,重寫了layerClass()方法,用來返回CAScrollLayer.這是個(gè)不常規(guī)的用來生成一個(gè)新layer并添加為子layer的方法.就像CALayer樣例里那樣.
2.設(shè)置一個(gè)屬性,能配合自定義UIView的滾動(dòng)視圖的layer進(jìn)行高效工作.
3.滾動(dòng)模式設(shè)為垂直水平都可以.
4.點(diǎn)擊時(shí),生成一個(gè)點(diǎn),這個(gè)滾動(dòng)layer就通過會(huì)動(dòng)畫滾動(dòng)到這個(gè)點(diǎn)的位置.單單scrollToPoint(:)
和scrollToRect(:)并不會(huì)生成動(dòng)畫
一個(gè)ScrollingView持有一張比本身的bounds大的圖片.運(yùn)行程序,點(diǎn)擊視圖就會(huì)有下面一樣的效果:
[圖片上傳失敗...(image-74955d-1587374045880)]
Layer Player有鎖定滾動(dòng)方向的功能.
下面是是CAScrollLayer的一些使用Tips:
1.當(dāng)你需要一個(gè)輕量的只需要程序來控制滾動(dòng)的東西時(shí),考慮一下CAScrollLayer.
2.如果你想用戶來操控滾動(dòng)時(shí),那么就用UIScrollView.這是關(guān)于UIScrollView的教程.上干貨
3.如果要滾動(dòng)超級(jí)無敵大的圖片,還是考慮用CATiledLayer吧.下面有講哦.
Example #3: CATextLayer
CATextLayer能夠快速高效簡(jiǎn)單地來渲染純文本或者attributed strings.不像UILable,CATextLayer沒有指定的UIFont,只有一個(gè)CTFontRef 或者 CGFontRef.
一段這樣的代碼能該改變字體,字體大小,顏色,對(duì)齊方式等等:
// 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.創(chuàng)建一個(gè)CATextLayer實(shí)例,bounds設(shè)為someView的bounds.
2.創(chuàng)建一段重復(fù)地文本,賦給這個(gè)textlayer
3.創(chuàng)建一個(gè)字體,賦給textlayer
4.設(shè)置文本環(huán)繞并且左對(duì)齊(你可以設(shè)為自然,右對(duì)齊.中心對(duì)齊,或者你覺得合理的).把它的contentsScale設(shè)為跟屏幕一樣.然后添加到layer的繼承樹里.
所有的layer類,包括CATextLayer,都是在默認(rèn)1的縮放比例下渲染的.當(dāng)本來就是屬于某個(gè)視圖里時(shí),layer會(huì)自動(dòng)把他們的contentsScale調(diào)整到對(duì)當(dāng)前屏幕來說合理的縮放比例.手動(dòng)創(chuàng)建的layer需要你顯示地調(diào)整contentsScale,否則縮放比例一直是1,在視網(wǎng)膜屏看起來就會(huì)模糊蛋疼.
如果添加到了一個(gè)方形的someView,那么生成的文本是這個(gè)樣子的:
[圖片上傳失敗...(image-6f9b48-1587374045880)]
高興得時(shí)候你可以用省略號(hào)來代表被剪切的文本.(截?cái)?Truncation默認(rèn)是沒有的,你可以設(shè)在開頭,中間,或者結(jié)尾.看下面示意圖:
[圖片上傳失敗...(image-a12b3b-1587374045880)]
[圖片上傳失敗...(image-ece582-1587374045880)]
[圖片上傳失敗...(image-fe6061-1587374045880)]
Layer Player有許多能操作CATextLayer屬性的控制功能:
[圖片上傳失敗...(image-9b6cd9-1587374045880)]
Example #4: AVPlayerLayer
AVPlayerLayer有一個(gè)用來播放av多媒體文件的avplayer(AVPlayerItems).
下面是個(gè)例子:
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
AVPlayerItemplayerItem.seekToTime(kCMTimeZero)
}
代碼分析:
1.創(chuàng)建新的player layer,設(shè)置frame
2.用一個(gè)AV資源創(chuàng)建一個(gè)player
3.告訴player結(jié)束時(shí)神馬都不做.可選的操作有:如暫停播放下一個(gè)項(xiàng)目
4.注冊(cè)AVPlayer當(dāng)播放結(jié)束時(shí)的通知.(銷毀時(shí)移除監(jiān)聽通知)
5.播放按鈕點(diǎn)下時(shí),觸發(fā)播放控制并設(shè)置按鈕的標(biāo)題.
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Lucida Grande'; color: #4e4e4e; -webkit-text-stroke: #4e4e4e}span.s1 {font-kerning: none}
AVPlayerLayer 和其上面創(chuàng)建的 AVPlayer 會(huì)直觀地表示 AVPlayerItem 實(shí)例的第一個(gè)幀:
[圖片上傳失敗...(image-ff4069-1587374045880)]
AVPlayerLayer有一對(duì)額外的屬性:
videoGravity :設(shè)置視頻顯示的大小調(diào)整行為
videoGravity :確認(rèn)視頻是否可以播放
AVPlayer,另一面它有不少額外的屬性和方法.一個(gè)就是播放速率,從0到1的速度.0是暫停,1是正常(1x).
暫停就是把播放速率設(shè)為0,播放就是設(shè)為1.那么快進(jìn)呢,慢動(dòng)作呢,循環(huán)播放呢.AVPlayerLayer都已經(jīng)想到了.設(shè)為2就是2倍快進(jìn),負(fù)當(dāng)然是慢動(dòng)作了.
當(dāng)不以正常速度播放時(shí),最好先確認(rèn)一下AVPlayerItem可以以一下速率播放:
canPlayFastForward()
canPlaySlowForward()
canPlayReverse()
canPlaySlowReverse()
canPlayFastReverse()
大多數(shù)視頻都可以快進(jìn),但是可以倒退播放的視頻不多見.Layer Player當(dāng)然也有播放可控制功能:
[圖片上傳失敗...(image-7dbf1c-1587374045880)]
Example #5: CAGradientLayer
CAGradientLayer能輕易地混合多種顏色,所以很適合用來當(dāng)背景.如何設(shè)置呢,你給他一個(gè)CGColor的數(shù)組,還有一個(gè)開始點(diǎn)和結(jié)束點(diǎn).
記住,開始點(diǎn)和結(jié)束點(diǎn)不是清楚的點(diǎn).他們定義在layer的bounds中.x為1表示在這個(gè)layer的右邊緣上,y是1的話就說明在layer的底部線上.
CAGradientLayer有個(gè)type屬性,雖然只有一個(gè)kCAGradientLayerAxial選項(xiàng),它線性地轉(zhuǎn)換數(shù)組里的顏色.
這表示如果你在開始點(diǎn)和結(jié)束點(diǎn)中間畫了條線,漸進(jìn)性會(huì)出現(xiàn)在A線,而B線上的顏色都是一樣的:
[圖片上傳失敗...(image-75b3f3-1587374045880)]
你可以通過一個(gè)值介于0到1的數(shù)組控制locations屬性.
下面是創(chuàng)建gradient layer的代碼:
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
}
上面的代碼創(chuàng)建了一個(gè)gradient layer,將layer的frame匹配someView的bounds.指定一組顏色,設(shè)置開始點(diǎn)和結(jié)束點(diǎn),把layer添加到視圖的layer上,最后長(zhǎng)這個(gè)樣子:
[圖片上傳失敗...(image-db54bd-1587374045880)]
叼炸天!
Layer Player也有這些功能哦:
[圖片上傳失敗...(image-a8c7dc-1587374045880)]
Example #6: CAReplicatorLayer
CAReplicatorLayer能復(fù)制一個(gè)layer指定的次數(shù),又能做出酷炫的效果了.
每一個(gè)layer拷貝可以有他自己的位置和顏色變化,可以推遲其繪圖動(dòng)畫效果給整體復(fù)制器層。此外可以保存深度,使復(fù)制層具有 3D 效果。下面是一個(gè)示例 ︰
// 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.創(chuàng)建一個(gè)CAReplicatorLayer實(shí)例,把bounds與someView的匹配.
2.設(shè)置這個(gè)重復(fù)器layer拷貝的數(shù)量(instanceCount),然后延遲繪制.設(shè)這個(gè)重復(fù)器layer的深度為2D(preservesDepth = false),設(shè)置拷貝的顏色為白色
3.給每個(gè)連續(xù)被拷貝的實(shí)例的RGB顏色的值添加offsets值.每個(gè)顏色offset值默認(rèn)是0,添加了之后就會(huì)影響每一個(gè)實(shí)例.這個(gè)例子當(dāng)中,實(shí)例起初就被設(shè)為白色,所以紅,綠,藍(lán)的值都是1.之后紅的又被改成了0,綠和藍(lán)被改成了負(fù)數(shù),這樣會(huì)讓紅色成為一個(gè)亮眼的顏色.同樣的,透明度也加到了每個(gè)連續(xù)的被拷貝對(duì)象上.
4.把所有被復(fù)制實(shí)例旋轉(zhuǎn)變換成一個(gè)圓
5.創(chuàng)建一個(gè)layer,bounds改成能讓第一個(gè)被復(fù)制的對(duì)象居于中上方的位置,好放下組成的整個(gè)圓
6.做一個(gè)透明度從0到1的漸變動(dòng)畫
7.把后來創(chuàng)建的layer的不可見度調(diào)到0
[圖片上傳失敗...(image-aeca2-1587374045880)]
[圖片上傳失敗...(image-96c8fe-1587374045880)]
Example #7: CATiledLayer
CATiledLayer異步地一塊一塊地繪制內(nèi)容.對(duì)超級(jí)大的圖像或者很多內(nèi)容在某個(gè)時(shí)刻只看它一小塊的情況很有效果.不用每次看的時(shí)候就立馬把整個(gè)內(nèi)容加載到內(nèi)存里,每次加載一部分.
有很多繪制的方法.一種就是是重寫UIView,用CATiledLayer重復(fù)地繪制一塊一塊的內(nèi)容,然后填充到背景里,像這樣:
// In ViewController.swift
import UIKit
class ViewController: UIViewController {
// 1
@IBOutlet weak var tiledBackgroundView:
TiledBackgroundView!
}
// In TiledBackgroundView.swift
import UIKit
class TiledBackgroundView: UIView {
let sideLength = CGFloat(50.0)
// 2
override class func layerClass() -> AnyClass {
return CATiledLayer.self
}
// 3
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
srand48(Int(NSDate().timeIntervalSince1970))
let layer = self.layer as CATiledLayer
let scale = UIScreen.mainScreen().scale
layer.contentsScale = scale
layer.tileSize = CGSize(width: sideLength * scale, height: sideLength * scale)
}
// 4
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
var red = CGFloat(drand48())
var green = CGFloat(drand48())
var blue = CGFloat(drand48())
CGContextSetRGBFillColor(context, red, green, blue, 1.0) CGContextFillRect(context, rect)
}
}
來看一下:
1.tiledBackgroundView放在點(diǎn)(150.150),寬高都是300.
2.layerClass()被重寫了,這樣這個(gè)view的layer就會(huì)變成CATiledLayer類
3.rand48()用來在drawRect()里生成隨機(jī)色,把scales與屏幕匹配,并設(shè)置繪制塊的大小
4.重寫drawRect(),用隨機(jī)色填充背景
最后代碼繪制一個(gè)6x6的顏色方塊:
[圖片上傳失敗...(image-217d0d-1587374045880)]
Layer Player還在上面畫了一條路徑:
[圖片上傳失敗...(image-140437-1587374045881)]
放大上面的星星,你會(huì)發(fā)現(xiàn)細(xì)節(jié)處變得模糊了:
[圖片上傳失敗...(image-a37087-1587374045881)]
模糊的原因是layer保持的細(xì)節(jié)量(levelsOfDetail)不高.CATiledLayer有兩個(gè)相關(guān)的屬性,levelsOfDetail 和 levelsOfDetailBias.
levelsOfDetail,表示所持有的細(xì)節(jié)量.一般默認(rèn)是1,最大值就是最底層每個(gè)細(xì)節(jié)都有一個(gè)像素.
levelsOfDetailBias,是這個(gè)layer緩存的放大級(jí)別的細(xì)節(jié)的數(shù)量.默認(rèn)0.
舉個(gè)栗子,把上面的例子的levelsOfDetailBias弄成5,會(huì)把緩存等級(jí)提高到2x, 4x, 8x, 16x 和32x,縮放后看起來像這樣:
[圖片上傳失敗...(image-150bfd-1587374045881)]
接下來講一下CATiledLayer對(duì)于滾動(dòng)超大圖片的用處.
雖然你需要給這個(gè)layer提供繪制方塊,和當(dāng)用戶拖動(dòng)時(shí)哪塊方塊抓住的邏輯,感覺很麻煩.但是它帶來的性能提升是非常大的.
Layer Player的UIImage+TileCutter.swift里有一個(gè)UIImage extension..它的工作是把源圖片切割成特定大小的方塊,然后根據(jù)行和列起名.比如下面那個(gè)清晰的方塊就是3行7列:
[圖片上傳失敗...(image-4777bb-1587374045881)]
通過放置這些方塊就可以創(chuàng)建這個(gè)方塊layer了:
import UIKit
class TilingViewForImage: UIView {
// 1
let sideLength = CGFloat(640.0)
let fileName = "windingRoad"
let cachesPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true)[0] as String
// 2
override class func layerClass() -> AnyClass {
return CATiledLayer.self
}
// 3
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let layer = self.layer as CATiledLayer
layer.tileSize = CGSize(width: sideLength, height: sideLength)
}
// 4
override func drawRect(rect: CGRect) {
let firstColumn = Int(CGRectGetMinX(rect) / sideLength)
let lastColumn = Int(CGRectGetMaxX(rect) / sideLength)
let firstRow = Int(CGRectGetMinY(rect) / sideLength)
let lastRow = Int(CGRectGetMaxY(rect) / sideLength)
for row in firstRow...lastRow {
for column in firstColumn...lastColumn {
if let tile = imageForTileAtColumn(column, row: row) {
let x = sideLength * CGFloat(column)
let y = sideLength * CGFloat(row)
let point = CGPoint(x: x, y: y)
let size = CGSize(width: sideLength, height: sideLength)
var tileRect = CGRect(origin: point, size: size)
tileRect = CGRectIntersection(bounds, tileRect)
tile.drawInRect(tileRect)
}
}
}
}
func imageForTileAtColumn(column: Int, row: Int) -> UIImage? {
let filePath = "\(cachesPath)/\(fileName)_\(column)_\(row)"
return UIImage(contentsOfFile: filePath)
}
}
上面代碼:
1.創(chuàng)建邊長(zhǎng),圖片的文件名和方塊切割的緩存的路徑這三個(gè)屬性.
2.重寫 layerClass()返回 CATiledLayer.
3.實(shí)現(xiàn)init(_:)
4.重寫drawRect(),讓它根據(jù)行列位置進(jìn)行繪制
然后把該子類的視圖的大小調(diào)到圖片大小,添加到一個(gè)scrollview:
[圖片上傳失敗...(image-efdf6-1587374045881)]
然后你就有了一個(gè)大圖像的平滑滾動(dòng)了:
[圖片上傳失敗...(image-9ff033-1587374045881)]
快速拖動(dòng)時(shí),你能明顯地看到是一塊一塊出現(xiàn)的.要減弱這個(gè)效果的話,可以把繪制塊的大小變小,創(chuàng)建一個(gè)CATiledLayer子類,重寫fadeDuration()方法返回0:
class TiledLayer: CATiledLayer {
override class func fadeDuration() -> CFTimeInterval {
return 0.0
}
}
Example #8: CAShapeLayer
CAShapeLayer利用可伸縮矢量路徑進(jìn)行繪制,它比使用圖片快得多。更好的是,你不用再提供圖片的正常 @2x @3x版本了.
另外,你有各種各樣的屬性用來定義自定義線的粗細(xì),顏色,如何加入其他的線,如果線相交形成一個(gè)封閉的區(qū)域,應(yīng)填什么顏色。下面是一個(gè)例子:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var someView: UIView!
// 1
let rwColor = UIColor(red: 11/255.0, green: 86/255.0, blue: 14/255.0, alpha: 1.0)
let rwPath = UIBezierPath()
let rwLayer = CAShapeLayer()
// 2
func setUpRWPath() {
rwPath.moveToPoint(CGPointMake(0.22, 124.79))
rwPath.addLineToPoint(CGPointMake(0.22, 249.57))
rwPath.addLineToPoint(CGPointMake(124.89, 249.57))
rwPath.addLineToPoint(CGPointMake(249.57, 249.57))
rwPath.addLineToPoint(CGPointMake(249.57, 143.79))
rwPath.addCurveToPoint(CGPointMake(249.37, 38.25), controlPoint1: CGPointMake(249.57, 85.64), controlPoint2: CGPointMake(249.47, 38.15))
rwPath.addCurveToPoint(CGPointMake(206.47, 112.47), controlPoint1: CGPointMake(249.27, 38.35), controlPoint2: CGPointMake(229.94, 71.76))
rwPath.addCurveToPoint(CGPointMake(163.46, 186.84), controlPoint1: CGPointMake(182.99, 153.19), controlPoint2: CGPointMake(163.61, 186.65))
rwPath.addCurveToPoint(CGPointMake(146.17, 156.99), controlPoint1: CGPointMake(163.27, 187.03), controlPoint2: CGPointMake(155.48, 173.59))
rwPath.addCurveToPoint(CGPointMake(128.79, 127.08), controlPoint1: CGPointMake(136.82, 140.43), controlPoint2: CGPointMake(129.03, 126.94))
rwPath.addCurveToPoint(CGPointMake(109.31, 157.77), controlPoint1: CGPointMake(128.59, 127.18), controlPoint2: CGPointMake(119.83, 141.01))
rwPath.addCurveToPoint(CGPointMake(89.83, 187.86), controlPoint1: CGPointMake(98.79, 174.52), controlPoint2: CGPointMake(90.02, 188.06))
rwPath.addCurveToPoint(CGPointMake(56.52, 108.28), controlPoint1: CGPointMake(89.24, 187.23), controlPoint2: CGPointMake(56.56, 109.11))
rwPath.addCurveToPoint(CGPointMake(64.02, 102.25), controlPoint1: CGPointMake(56.47, 107.75), controlPoint2: CGPointMake(59.24, 105.56))
rwPath.addCurveToPoint(CGPointMake(101.42, 67.57), controlPoint1: CGPointMake(81.99, 89.78), controlPoint2: CGPointMake(93.92, 78.72))
rwPath.addCurveToPoint(CGPointMake(108.38, 30.65), controlPoint1: CGPointMake(110.28, 54.47), controlPoint2: CGPointMake(113.01, 39.96))
rwPath.addCurveToPoint(CGPointMake(10.35, 0.41), controlPoint1: CGPointMake(99.66, 13.17), controlPoint2: CGPointMake(64.11, 2.16))
rwPath.addLineToPoint(CGPointMake(0.22, 0.07))
rwPath.addLineToPoint(CGPointMake(0.22, 124.79))
rwPath.closePath() }
// 3
func setUpRWLayer() {
rwLayer.path = rwPath.CGPath
rwLayer.fillColor = rwColor.CGColor
rwLayer.fillRule = kCAFillRuleNonZero
rwLayer.lineCap = kCALineCapButt
rwLayer.lineDashPattern = nil
rwLayer.lineDashPhase = 0.0
rwLayer.lineJoin = kCALineJoinMiter
rwLayer.lineWidth = 1.0
rwLayer.miterLimit = 10.0
rwLayer.strokeColor = rwColor.CGColor
}
override func viewDidLoad() {
super.viewDidLoad()
// 4
setUpRWPath()
setUpRWLayer()
someView.layer.addSublayer(rwLayer)
}
}
解釋代碼:
1.創(chuàng)建顏色路徑shapelayer對(duì)象
2.繪制路徑
3.設(shè)置layer,它的路徑被設(shè)為第二步的路徑,填充色設(shè)為第一步里設(shè)置的顏色,填充規(guī)則被顯式地設(shè)置為非零的默認(rèn)值。
唯一的其他選擇是even-odd,并且對(duì)于這個(gè)形狀,沒有交叉的路徑填充規(guī)則讓差異變得很小。
非零規(guī)則把從左至右的路徑記為+ 1從右至左的路徑為1,它總和了所有的路徑,如果和大于0,那他就根據(jù)路徑填充顏色.
從本質(zhì)上講,非零填充這個(gè)形狀的所有點(diǎn)。
even-odd規(guī)則計(jì)數(shù)形成一個(gè)形狀的路徑的總數(shù),如果最后是奇數(shù),則該形狀被填充。當(dāng)一個(gè)圖片是一千字時(shí),這絕對(duì)是個(gè)列子。
形成這個(gè)五角星的路徑交點(diǎn)的總數(shù)是偶數(shù),所以沒有被填充.而形成每個(gè)三角形的路徑的交點(diǎn)是奇數(shù),所以該三角形被填充。
[圖片上傳失敗...(image-68bbe5-1587374045881)]
[圖片上傳失敗...(image-6f229b-1587374045881)]
我們跳過了Layer Player里的下一個(gè)demo.因?yàn)镃AEAGLLayer已經(jīng)被CAMetalLayer替代了.這里有相關(guān)教程.
Example #9: CATransformLayer
CATransformLayer不平鋪它的子layer,它很適合3D結(jié)構(gòu)的視圖.CATransformLayer實(shí)際是子layer的一個(gè)容器,每個(gè)子layer有自己的形變和透明度,但,類似線框?qū)挾群皖伾膌ayer屬性會(huì)被忽略掉.
因?yàn)镃ATransformLayer沒有2維坐標(biāo)系,所以沒辦法檢測(cè)點(diǎn)擊.但是在獨(dú)立的子layer里可以檢測(cè)到.舉個(gè)栗子:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var someView: UIView!
// 1
let sideLength = CGFloat(160.0)
var redColor = UIColor.redColor()
var orangeColor = UIColor.orangeColor()
var yellowColor = UIColor.yellowColor()
var greenColor = UIColor.greenColor()
var blueColor = UIColor.blueColor()
var purpleColor = UIColor.purpleColor()
var transformLayer = CATransformLayer()
// 2
func setUpTransformLayer() {
var layer = sideLayerWithColor(redColor)
transformLayer.addSublayer(layer)
layer = sideLayerWithColor(orangeColor)
var transform = CATransform3DMakeTranslation(sideLength / 2.0, 0.0, sideLength / -2.0)
transform = CATransform3DRotate(transform, degreesToRadians(90.0), 0.0, 1.0, 0.0)
layer.transform = transform
transformLayer.addSublayer(layer)
layer = sideLayerWithColor(yellowColor)
layer.transform = CATransform3DMakeTranslation(0.0, 0.0, -sideLength)
transformLayer.addSublayer(layer)
layer = sideLayerWithColor(greenColor)
transform = CATransform3DMakeTranslation(sideLength / -2.0, 0.0, sideLength / -2.0)
transform = CATransform3DRotate(transform, degreesToRadians(90.0), 0.0, 1.0, 0.0)
layer.transform = transform
transformLayer.addSublayer(layer)
layer = sideLayerWithColor(blueColor)
transform = CATransform3DMakeTranslation(0.0, sideLength / -2.0, sideLength / -2.0)
transform = CATransform3DRotate(transform, degreesToRadians(90.0), 1.0, 0.0, 0.0)
layer.transform = transform
transformLayer.addSublayer(layer)
layer = sideLayerWithColor(purpleColor)
transform = CATransform3DMakeTranslation(0.0, sideLength / 2.0, sideLength / -2.0)
transform = CATransform3DRotate(transform, degreesToRadians(90.0), 1.0, 0.0, 0.0)
layer.transform = transform
transformLayer.addSublayer(layer)
transformLayer.anchorPointZ = sideLength / -2.0
applyRotationForXOffset(16.0, yOffset: 16.0)
}
// 3
func sideLayerWithColor(color: UIColor) -> CALayer {
let layer = CALayer()
layer.frame = CGRect(origin: CGPointZero, size: CGSize(width: sideLength, height: sideLength))
layer.position = CGPoint(x: CGRectGetMidX(someView.bounds), y: CGRectGetMidY(someView.bounds))
layer.backgroundColor = color.CGColor return layer }
func degreesToRadians(degrees: Double) -> CGFloat {
return CGFloat(degrees * M_PI / 180.0)
}
// 4
func applyRotationForXOffset(xOffset: Double, yOffset: Double) {
let totalOffset = sqrt(xOffset * xOffset + yOffset * yOffset)
let totalRotation = CGFloat(totalOffset * M_PI / 180.0) let xRotationalFactor = CGFloat(totalOffset) / totalRotation
let yRotationalFactor = CGFloat(totalOffset) / totalRotation
let currentTransform = CATransform3DTranslate(transformLayer.sublayerTransform, 0.0, 0.0, 0.0)
let rotationTransform = CATransform3DRotate(transformLayer.sublayerTransform, totalRotation, xRotationalFactor * currentTransform.m12 - yRotationalFactor * currentTransform.m11, xRotationalFactor * currentTransform.m22 - yRotationalFactor * currentTransform.m21, xRotationalFactor * currentTransform.m32 - yRotationalFactor * currentTransform.m31)
transformLayer.sublayerTransform = rotationTransform
}
// 5
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if let location = touches.anyObject()?.locationInView(someView) {
for layer in transformLayer.sublayers {
if let hitLayer = layer.hitTest(location) {
println("Transform layer tapped!") break }
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// 6
setUpTransformLayer()
someView.layer.addSublayer(transformLayer)
}
}
解釋代碼:
1.為邊長(zhǎng),顏色,方塊的每個(gè)面創(chuàng)建屬性和一個(gè)transform layer
2.通過創(chuàng)建旋轉(zhuǎn)面并添加到這個(gè)transform layer來產(chǎn)生方塊.然后設(shè)置transform layerz軸的錨點(diǎn),旋轉(zhuǎn)方塊,添加到視圖繼承樹里.
3.創(chuàng)建幫助器代碼來用指定的顏色創(chuàng)建每個(gè)方塊面layer并將度轉(zhuǎn)換為弧度。為什么是弧度?因?yàn)槲矣X得它更直觀。
4.應(yīng)用一個(gè)基于x和y偏移的旋轉(zhuǎn).注意看下,代碼把變形設(shè)到了子layerTransform上,而且應(yīng)用于transform layer的子layer。
5.檢查transform layer里的觸摸.
6.設(shè)置并添加到view里
note:currentTransform.m##這些是什么?這些都是矩陣代表包括矩形數(shù)組的行和列的元素的 CATransform3D 屬性.想了解更多的話點(diǎn)我.
運(yùn)行程序,看下這個(gè)250x250的view:
[圖片上傳失敗...(image-ec6bf5-1587374045881)]
Layer Player :
[圖片上傳失敗...(image-7ce231-1587374045881)]
Example #10: CAEmitterLayer
總算到最后一個(gè)了.
CAEmitterLayer 渲染 CAEmitterCell 實(shí)例的具有動(dòng)畫性的粒子。CAEmitterLayer 和 CAEmitterCell 有更改渲染速率、 大小、 形狀、 顏色、 速度、 生命周期和更多的屬性。
栗子:
import UIKit
class ViewController: UIViewController {
// 1
let emitterLayer = CAEmitterLayer()
let emitterCell = CAEmitterCell()
// 2
func setUpEmitterLayer() {
emitterLayer.frame = view.bounds
emitterLayer.seed = UInt32(NSDate().timeIntervalSince1970)
emitterLayer.renderMode = kCAEmitterLayerAdditive
emitterLayer.drawsAsynchronously = true
setEmitterPosition()
}
// 3
func setUpEmitterCell() {
emitterCell.contents = UIImage(named: "smallStar")?.CGImage
emitterCell.velocity = 50.0
emitterCell.velocityRange = 500.0
emitterCell.color = UIColor.blackColor().CGColor
emitterCell.redRange = 1.0
emitterCell.greenRange = 1.0
emitterCell.blueRange = 1.0
emitterCell.alphaRange = 0.0
emitterCell.redSpeed = 0.0
emitterCell.greenSpeed = 0.0
emitterCell.blueSpeed = 0.0
emitterCell.alphaSpeed = -0.5
let zeroDegreesInRadians = degreesToRadians(0.0)
emitterCell.spin = degreesToRadians(130.0)
emitterCell.spinRange = zeroDegreesInRadians
emitterCell.emissionRange = degreesToRadians(360.0)
emitterCell.lifetime = 1.0
emitterCell.birthRate = 250.0
emitterCell.xAcceleration = -800.0
emitterCell.yAcceleration = 1000.0
}
// 4
func setEmitterPosition() {
emitterLayer.emitterPosition = CGPoint(x:CGRectGetMidX(view.bounds), y: CGRectGetMidY(view.bounds))
}
func degreesToRadians(degrees: Double) -> CGFloat {
return CGFloat(degrees * M_PI / 180.0)
}
override func viewDidLoad() {
super.viewDidLoad()
// 5
setUpEmitterLayer()
setUpEmitterCell()
emitterLayer.emitterCells = [emitterCell]
view.layer.addSublayer(emitterLayer) }
// 6
override func traitCollectionDidChange(previousTraitCollection:UITraitCollection?) {
setEmitterPosition()
}
}
解釋代碼:
1.創(chuàng)建 emitter layer 和cell
2.通過以下操作設(shè)置emitter layer
1. 為圖層用來給cell的屬性(比如速度)值隨機(jī)化的隨機(jī)數(shù)發(fā)生器提供了一個(gè)seed。下一條進(jìn)一步解釋了這個(gè)問題。
2. 上面的渲染粒子cell(Renders emitter cell),他們的背景色 ,線寬是根據(jù)renderMode按順序確定的.
注意點(diǎn)---蘋果文檔目前不正確地指出,此屬性的值定義在Emitter Modes模式下。事實(shí)上,renderMode定義在Emitter Render Order下。默認(rèn)值是unordered, 其他的值有oldest first(最老的優(yōu)先), oldest last, back to front 和 additive.
3.drawsAsynchronously設(shè)為true.這個(gè)操作能夠提高性能,發(fā)射器是持續(xù)不斷地重繪它的cell的.
4.通過setEmitterPosition()來設(shè)置emitter的位置
3.這一塊代碼有很多操作:
1.設(shè)置emitter cell的內(nèi)容為一張圖片(這張圖片Layer Player里有)
2.然后它指定初始速度和最大的方差 (velocityRange).emitter layer使用上面的種子創(chuàng)建了一個(gè)在這個(gè)范圍內(nèi)隨機(jī)生成值的隨機(jī)數(shù)發(fā)生器.
3.把顏色設(shè)置為黑色,允許從默認(rèn)的白色開始變化,因?yàn)榘咨^于明亮。
4.下一步是用相同的隨機(jī)器設(shè)置一系列顏色范圍,這一次是把變化的范圍指定給每個(gè)顏色.速度表示顏色變化得有多快.
5.設(shè)置cell的旋轉(zhuǎn)速率和發(fā)射范圍.發(fā)射范圍決定了emitter cells如何在給定的emissionRange里分布
6.cell生命周期改為1,表示1秒,默認(rèn)是0.所以你如果不改的話就看不到效果了.還有生出速率,默認(rèn)也是0.這里也要改成正數(shù),否則也是沒效果的.
4.將度轉(zhuǎn)換為弧度,將發(fā)射器cell的位置設(shè)置為視圖的中點(diǎn)。
5.全部設(shè)置好,加到該加的地方
6.這個(gè)方法是iOS8的新方法,提供了一個(gè)方法來處理當(dāng)前的特征集合,比如旋轉(zhuǎn)設(shè)備。不熟悉特征集合嗎?查閱iOS 8 by Tutorials.
運(yùn)行:
[圖片上傳失敗...(image-fd09c0-1587374045881)]
Layer Player:
[圖片上傳失敗...(image-b56960-1587374045881)]
干貨上完啦
[圖片上傳失敗...(image-6d1a9e-1587374045881)]