這是 Core Animation 的系列文章伙狐,介紹了 Core Animation 的用法茧跋,以及如何進(jìn)行性能優(yōu)化伟姐。
我們已經(jīng)介紹了CALayer
類杨刨、CGAffineTransform、CATransform3D擦剑,但 Core Animation 圖層不止用于設(shè)置圖片妖胀、背景色芥颈。這一篇文章介紹一些圖層類,進(jìn)一步擴(kuò)展 Core Animation 的能力赚抡。
1. CAShapeLayer
在第一篇文章CoreAnimation基本介紹中爬坑,介紹了使用CGPath
創(chuàng)建任意形狀的陰影,無需使用圖片涂臣。如果可以創(chuàng)建任意形狀圖層就更好了盾计。
CAShapeLayer
在其坐標(biāo)空間中繪制三次貝塞爾曲線圖層,繼承自CALayer
赁遗。
CAShapeLayer
在 layer 的 contents 和第一個 sublayer 之間合成署辉,CAShapeLayer
通過矢量圖形而非位圖繪制。使用CGPath
指定顏色岩四、線寬和形狀哭尝,CAShapeLayer
自動渲染圖層。你也可以使用 Core Graphics 直接向CALayer
的contents
繪制路徑剖煌,但使用CAShapeLayer
有以下這些優(yōu)點(diǎn):
快速材鹦。
CAShapeLayer
使用硬件加速,比使用 Core Graphics 繪制速度快耕姊。節(jié)省內(nèi)存桶唐。
CAShapeLayer
無需像CALayer
那樣創(chuàng)建 backing image。因此箩做,不會隨著 layer 變大莽红,占用更大內(nèi)存。超出 layer 邊框部分不會被裁剪邦邦。
CAShapeLayer
可以在bounds
外繪制,不會像使用 Core Graphics 在CALayer
繪制的圖形一樣被裁剪掉醉蚁。旋轉(zhuǎn)燃辖、縮放等變換操作后不會失真。由于
CAShapeLayer
是矢量圖(Vector graphics)网棍,可以通過數(shù)學(xué)公式計(jì)算獲得黔龟。放大時,不會像位圖(bitmap)那樣放大單個像素滥玷,也就不會出現(xiàn)線條或形狀鋸齒化的問題氏身。
1.1 創(chuàng)建 CGPath
CAShapeLayer
可用于繪制任何可用CGPath
表示的形狀。圖形不一定閉合惑畴,路徑不一定連續(xù)蛋欣,可以在一個CAShapeLayer
中添加多個 shape。
設(shè)置一些屬性可以改變CAShapeLayer
樣式如贷,如fillColor
陷虎、strokeColor
到踏、lineWidth
、lineCap
(線末端樣式)尚猿、lineJoin
(線之間接頭樣式)等窝稿,但一個CAShapeLayer
只能有一個fillColor
、lineDashPattern
凿掂、lineJoin
等伴榔。如果需使用不同樣式、顏色庄萎,需創(chuàng)建多個 shape layer潮梯。
下面代碼顯示了使用CAShapeLayer
繪制線筆畫,CAShapeLayer
的path
屬性是CGPathRef
類型惨恭。這里使用UIBezierPath
創(chuàng)建 path秉馏,省去了手動釋放CGPath
的步驟。如下所示:
// Create path
let path = UIBezierPath()
path.move(to: CGPoint(x: 175, y: 100))
path.addArc(withCenter: CGPoint(x: 150, y: 100), radius: 25, startAngle: 0, endAngle: .pi * 2, clockwise: true)
path.move(to: CGPoint(x: 150, y: 125))
path.addLine(to: CGPoint(x: 150, y: 175))
path.addLine(to: CGPoint(x: 125, y: 225))
path.move(to: CGPoint(x: 150, y: 175))
path.addLine(to: CGPoint(x: 175, y: 225))
path.move(to: CGPoint(x: 100, y: 150))
path.addLine(to: CGPoint(x: 200, y: 150))
// Create shape layer
let shapelLayer = CAShapeLayer()
shapelLayer.strokeColor = UIColor.red.cgColor
shapelLayer.fillColor = UIColor.clear.cgColor
shapelLayer.lineWidth = 5
shapelLayer.lineJoin = .bevel
shapelLayer.lineCap = .round
shapelLayer.path = path.cgPath
// Add it to our view
view.layer.addSublayer(shapelLayer)
效果如下:
1.2 圓角
使用CAShapeLayer
可以創(chuàng)建圓角矩形脱羡。與cornerRadius
相比萝究,CAShapeLayer
允許指定單個角半徑。下面代碼創(chuàng)建三個圓角锉罐、一個直角的矩形:
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let radii = CGSize(width: 20, height: 20)
let path = UIBezierPath.init(roundedRect: rect, byRoundingCorners: [.topRight, .bottomRight, .bottomLeft], cornerRadii: radii)
為CAShapeLayer
的path
屬性設(shè)置上述貝塞爾曲線帆竹,可以獲得圓角、直角組合的矩形脓规。如果想要將 layer 的contents
設(shè)置為同樣圖形栽连,可以將CAShapeLayer
賦值給mask
屬性。如下所示:
// Create path
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let radii = CGSize(width: 20, height: 20)
let path = UIBezierPath.init(roundedRect: rect, byRoundingCorners: [.topRight, .bottomRight, .bottomLeft], cornerRadii: radii)
let layer = CALayer()
layer.backgroundColor = UIColor.gray.cgColor
layer.position = view.center
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
// Create mask layer
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
view.layer.addSublayer(layer)
效果如下:
CALayer
的mask
屬性是CALayer
類侨舆,使用方法與 sublayer 類似秒紧,相對于擁有它的圖層布局自身位置。與普通 sublayer 不同挨下,mask
不是在父圖層內(nèi)繪制熔恢,其決定了父圖層的可見區(qū)域。
mask
的顏色不重要臭笆,重要的是它的輪廓叙淌。與mask
重合部分會被保留下來,mask
以外部分會被隱藏愁铺。
如果mask
layer小于父圖層鹰霍,則只有與mask
相交的父圖層部分可見,其他部分都會被隱藏茵乱。
2. CATransformLayer
在 3D 場景中茂洒,創(chuàng)建對象的層級結(jié)構(gòu)并將變換應(yīng)用于根視圖,整個層級結(jié)構(gòu)會隨之變換似将。
向容器中添加四個圖層获黔,不添加任何變換蚀苛。如下所示:
旋轉(zhuǎn)每個 layer Y軸后,得到如下四個圖層:
CALayer
不能管理 3D 層級結(jié)構(gòu)中的深度玷氏,其只能將Z軸場景展平到單個層級堵未。為了解決這個問題,需使用CATransformLayer
盏触。
與其他 layer 不同渗蟹,CATransformLayer
不會將 sublayer 展平到 Z=0 的平面中,因此赞辩,它不支持CALayer
的眾多功能:
- 只渲染
CATransformLayer
的 sublayer雌芽。transform layer 的backgroundColor
、contents
辨嗽、邊緣樣式世落、描邊樣式等都不會生效。 - 2D 圖像處理的屬性會被忽略糟需。包含
filters
屉佳、backgroundFilters
、compositingFilter
洲押、mask
武花、masksToBounds
和陰影樣式等。 -
opacity
屬性會被單獨(dú)應(yīng)用到每個 sublayer杈帐,transform layer 不會形成合成組体箕。 - Transform layer 沒有 2D 坐標(biāo)空間概念,不能將自身點(diǎn)映射到二維空間挑童。因此累铅,不要對 transform layer 應(yīng)用
hitTest:
方法。
下面代碼創(chuàng)建了四個 layer炮沐,其具有相同的x争群、y坐標(biāo),不同z坐標(biāo)大年。
private func testTransformLayerA() {
// Create the container as a CATransformLayer
let container = CATransformLayer()
// 如果使用CALayer,不能得到三維圖層玉雾。
// let container = CALayer()
container.frame = view.frame
view.layer.addSublayer(container)
// Planes data
let planesPosition = view.layer.position
let planeSize = CGSize(width: 100, height: 100)
// Create 4 planes
let purplePlane = addPlane(to: container, size: planeSize, position: planesPosition, color: UIColor.purple)
let redPlane = addPlane(to: container, size: planeSize, position: planesPosition, color: UIColor.red)
let orangePlane = addPlane(to: container, size: planeSize, position: planesPosition, color: UIColor.orange)
let yellowPlane = addPlane(to: container, size: planeSize, position: planesPosition, color: UIColor.yellow)
// Apply transform to the container
var t = CATransform3DIdentity
t.m34 = 1.0 / -500
t = CATransform3DRotate(t, .pi/3, 0, 1, 0)
container.transform = t
// Apply transform to the planes
t = CATransform3DIdentity
t = CATransform3DTranslate(t, 0, 0, 0)
purplePlane.transform = t
// Apply transform to the planes
t = CATransform3DIdentity
t = CATransform3DTranslate(t, 0, 0, -40)
redPlane.transform = t
// Apply transform to the planes
t = CATransform3DIdentity
t = CATransform3DTranslate(t, 0, 0, -80)
orangePlane.transform = t
// Apply transform to the planes
t = CATransform3DIdentity
t = CATransform3DTranslate(t, 0, 0, -120)
yellowPlane.transform = t
}
private func addPlane(to container: CALayer, size: CGSize, position: CGPoint, color: UIColor) -> CALayer {
let plane = CALayer()
plane.backgroundColor = color.cgColor
plane.opacity = 0.6
plane.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
plane.position = position
plane.borderColor = UIColor.init(white: 1.0, alpha: 0.5).cgColor
plane.borderWidth = 3
plane.cornerRadius = 10
container.addSublayer(plane)
return plane
}
運(yùn)行結(jié)果如下:
如果使用CALayer
替代CATransformLayer
翔试,效果如下:
3. CAGradientLayer
CAGradientLayer
繪制背景色漸變的圖層。
Gradient layer 用于創(chuàng)建包含任意數(shù)量顏色的顏色漸變复旬。默認(rèn)情況下垦缅,顏色均勻分布在整個圖層上,但可以使用locations
屬性指定顏色位置驹碍。
CAGradientLayer
有以下屬性:
-
locations
:元素為浮點(diǎn)類型的數(shù)組壁涎,值范圍為0至1凡恍,且只能遞增。如果為nil
怔球,則均勻排布嚼酝。默認(rèn)為nil
。 -
colors
:元素為CGColorRef
類型的數(shù)組竟坛,默認(rèn)為nil
闽巩。 -
startPoint
:在圖層坐標(biāo)空間繪制時,漸變的起點(diǎn)担汤。使用單位坐標(biāo)系涎跨,并在繪制時映射到 layer 點(diǎn)坐標(biāo)。默認(rèn)值為(0.5, 0.5)崭歧。 -
endPoint
:在圖層坐標(biāo)空間繪制時隅很,漸變的終點(diǎn)。使用單位坐標(biāo)系率碾,并在繪制時映射到 layer 點(diǎn)坐標(biāo)叔营。默認(rèn)值為(0.5, 1.0)。
下面代碼展示了如何創(chuàng)建包含三種顏色播掷、指定漸變位置的圖層:
gradient.colors = [UIColor.red.cgColor, UIColor.yellow.cgColor, UIColor.green.cgColor]
gradient.locations = [0.0, 0.25, 0.5]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 1)
效果如下:
4. CAReplicatorLayer
CAReplicatorLayer
用于創(chuàng)建 layer 的指定數(shù)量副本审编,副本間有不同的幾何坐標(biāo)、顯示屬性(delay歧匈、transform)和顏色等垒酬。常用屬性如下:
-
instanceCount
:要創(chuàng)建的副本數(shù),包括原始 layer件炉。默認(rèn)值時1勘究,即不創(chuàng)建副本。 -
instanceDelay
:指定副本顯示延時斟冕。默認(rèn)值為0.0秒口糕,即同步顯示。 -
instanceTransform
:向前一個副本添加 transform磕蛇,得到當(dāng)前副本景描。默認(rèn)為CATransform3DIdentity
。 -
preservesDepth
:是否將子圖層展平到平面中秀撇。默認(rèn)為false
超棺。如果為true
,則CAReplicatorLayer
表現(xiàn)與CATransformLayer
相似呵燕,同時受CATransformLayer
同樣限制棠绘。 -
instanceColor
:指定原始圖層的顏色。默認(rèn)為不透明白色。 -
instanceRedOffset
:指定顏色紅色通道偏移量氧苍。向 k-1 實(shí)例添加偏移夜矗,得到 k 實(shí)例顏色。默認(rèn)為0.0让虐。
instanceGreenOffset
紊撕、instanceBlueOffset
、instanceAlphaOffset
與instanceRedOffset
類似澄干,只是通道不同逛揩。
下面的代碼在屏幕中央創(chuàng)建一個白色的 layer,使用CAReplicatorLayer
創(chuàng)建由十個 layer 構(gòu)成圓形的圖案麸俘。
var replicatorLayer = CAReplicatorLayer()
replicatorLayer.bounds = CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height)
view.layer.addSublayer(replicatorLayer)
// Configure the replicator
replicatorLayer.instanceCount = 10
// Apply a transform for each instance
var transform = CATransform3DIdentity
transform = CATransform3DTranslate(transform, 0, 200, 0)
transform = CATransform3DRotate(transform, .pi / 5.0, 0, 0, 1)
transform = CATransform3DTranslate(transform, 0, -200, 0)
replicatorLayer.instanceTransform = transform
// Apply a color shift for each instance
replicatorLayer.instanceBlueOffset = -0.1
replicatorLayer.instanceGreenOffset = -0.1
// Create a sublayer and place it inside the replicator
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.position = view.layer.position
layer.backgroundColor = UIColor.white.cgColor
replicatorLayer.addSublayer(layer)
效果如下:
CAReplicatorLayer
可用于游戲中導(dǎo)彈發(fā)射后軌跡辩稽、粒子發(fā)射效果。此外从媚,還可以用于鏡像圖片逞泄。
設(shè)置負(fù)值的縮放因子可以獲得鏡像。這里將其封裝為單獨(dú)視圖拜效,后續(xù)使用時只需繼承自ReflectionView
即可喷众。
class ReflectionView: UIView {
override class var layerClass: AnyClass {
return CAReplicatorLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
let layer = self.layer as! CAReplicatorLayer
layer.instanceCount = 2
// Move reflection instance below original and flip vertically
var transform = CATransform3DIdentity
let verticalOffset = self.bounds.size.height + 2
transform = CATransform3DTranslate(transform, 0, verticalOffset, 0)
transform = CATransform3DScale(transform, 1, -1, 0)
layer.instanceTransform = transform
// Reduce alpha of reflection layer
layer.instanceAlphaOffset = -0.6
}
}
效果如下:
開源項(xiàng)目ReflectionView實(shí)現(xiàn)了自適應(yīng)漸變淡出效果,淡出效果使用CAGradientLayer
和 mask 實(shí)現(xiàn)紧憾。
5. CAScrollLayer
對于沒有進(jìn)行變換的 layer到千,bounds
的大小與frame
的大小一致。frame
是由bounds
赴穗、position
派生而來憔四。因此,改變一個會影響另一個般眉。
如果想展示大圖層的一部分應(yīng)該如何做了赵?例如,有一個很大的圖片甸赃,或者一個長列表柿汛、文本,希望用戶可以隨意滑動埠对。在 iOS 中络断,可以使用UITableView
或UIScrollView
,Core Animation 中對應(yīng)的 layer 是什么呢项玛?
想要展示大圖一部分時妓羊,可以使用contentsRect
屬性,但當(dāng)你的圖層有 sublayer 時稍计,每次滑動時都需要手動計(jì)算、更新所有 sublayer 位置裕循,這樣非常麻煩臣嚣。
這時可以使用CAScrollLayer
净刮,CAScrollLayer
的scroll(to:)
方法自動調(diào)整bounds
的原點(diǎn),使圖層內(nèi)容看起來是在滑動硅则。由于 Core Animation 不能識別用戶手勢淹父,因此其不能將手勢轉(zhuǎn)換為滑動事件,另外也不會渲染滑動狀態(tài)條和滑動彈性效果怎虫。
下面使用CAScrollLayer
創(chuàng)建一個類似UIScrollView
的替代控件暑认。創(chuàng)建一個自定義UIView
,使用CAScrollLayer
作為 backing layer大审,使用UIPanGestureRecognizer
處理手勢蘸际。代碼如下:
class ScrollView: UIView {
override class var layerClass: AnyClass {
return CAScrollLayer.self
}
private func setup() {
// Enable clipping
layer.masksToBounds = true
backgroundColor = UIColor.lightGray
// Attach pan gesture recognizer
let recognizer = UIPanGestureRecognizer(target: self, action: #selector(self.pan(_:)))
addGestureRecognizer(recognizer)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
@objc func pan(_ recognizer: UIPanGestureRecognizer) {
// Get the offset by subtracting the pan gesture
// Transform from the current bounds origin
var offset = self.bounds.origin
offset.x -= recognizer.translation(in: self).x
offset.y -= recognizer.translation(in: self).y
// Scroll the layer
layer.scroll(offset)
// Reset the pan gesture translation
recognizer.setTranslation(CGPoint.zero, in: self)
}
}
如下所示:
CAScrollLayer
類的以下方法實(shí)現(xiàn)了滾動功能:
-
scroll(to: CGPoint)
:將 layer 的原點(diǎn)設(shè)置為指定點(diǎn)。 -
scroll(to: CGRect)
:滾動內(nèi)容徒扶,確保指定矩形區(qū)域可見粮彤。
我們使用CAScrollLayer
實(shí)現(xiàn)的 ScrollView 類沒有進(jìn)行任何邊界檢測,內(nèi)容可能會劃出可見區(qū)域并可繼續(xù)滾動姜骡。CAScrollLayer
沒有UIScrollView
中contentSize
概念导坟,因此沒有總可滑動區(qū)域概念。也就是劃動CAScrollLayer
時圈澈,它只是調(diào)整bounds
原點(diǎn)到指定位置惫周。
既然可以通過調(diào)整CALayer
的bounds
獲得同樣效果,什么情況下需要使用CAScrollLayer
康栈?事實(shí)上很少使用CAScrollLayer
递递,UIScrollView
沒有使用CAScrollLayer
,而是直接操控 layer 的bounds
進(jìn)行滾動谅将。
6. CATiledLayer
有時需要繪制的圖片特別大漾狼,而移動設(shè)備內(nèi)存非常有限,因此讀取整個圖片到內(nèi)存不是一種好的解決方案饥臂。
載入大圖會非常慢逊躁,常用的init(named:)
和contentsOfFile:
方法會堵塞主線程,導(dǎo)致卡頓隅熙。圖片最大大小受設(shè)備內(nèi)存限制稽煤。屏幕上顯示的圖片最終都會被轉(zhuǎn)換為 OpenGL texture,而 OpenGL texture 有一個最大的大星羝荨(通常為2048*2048或4096*4096酵熙,因設(shè)備而異)。
如果要顯示的圖片大于單個 texture驰坊,即使圖片已經(jīng)存在于內(nèi)存中了匾二,Core Animation 也必須使用 CPU 而非 GPU 處理圖片,這時會明顯感受到內(nèi)存問題。
CATiledLayer
通過把大圖分割為小圖解決上述性能問題察藐。當(dāng)需要渲染更多區(qū)域時皮璧,在一個或多個后臺線程調(diào)用draw(in:)
方法,為繪制操作提供數(shù)據(jù)分飞。Drawing context 提供了 clip bounds 和 transform matrix悴务,用于確定請求圖塊的分辨率和 bounds。
使用setNeedsDisplay(_:)
方法使圖層指定區(qū)域無效譬猫,但更新是異步的讯檐。且下一次的更新很可能不包含更新的內(nèi)容,但后續(xù)的更新會包含染服。
6.1 顯示多個小圖
下面展示一張大圖(2048*2048)别洪。為了獲得CATiledLayer
的性能提升,需將大圖分割為多張小圖肌索。雖然可以使用代碼分割圖片蕉拢,但如果在運(yùn)行時加載圖片并分割,將會失去CATiledLayer
提供的性能提升诚亚。這里直接使用分割好的小圖晕换,小圖大小為256*256,共64張站宗。
把CATiledLayer
添加到UIScrollView
使用闸准,并實(shí)現(xiàn)draw(in:)
方法。當(dāng)CATiledLayer
需要加載新圖片時梢灭,會調(diào)用draw(in:)
方法夷家。
private func testTiledLayer() {
view.addSubview(scrollView)
// Add the tiled layer
let tileLayer = CATiledLayer()
tileLayer.frame = CGRect(x: 0, y: 0, width: 2048, height: 2048)
tileLayer.delegate = self
scrollView.layer.addSublayer(tileLayer)
// Configure the scroll view.
scrollView.contentSize = tileLayer.frame.size
// Draw layer
tileLayer.setNeedsDisplay()
}
extension LayersViewController: CALayerDelegate {
func draw(_ layer: CALayer, in ctx: CGContext) {
guard let layer = layer as? CATiledLayer else {
return
}
// Determine tile coordinate
let bounds = ctx.boundingBoxOfClipPath
let x: Int = Int(floor(bounds.origin.x / layer.tileSize.width))
let y: Int = Int(floor(bounds.origin.y / layer.tileSize.height))
// Load tile image
let imgName = "Snowman_0\(x)_0\(y)"
let imgPath = Bundle.main.path(forResource: imgName, ofType: "jpg")
guard let imgLocation = imgPath else { return }
let tileImage = UIImage(contentsOfFile: imgLocation)
// Draw tile
UIGraphicsPushContext(ctx)
tileImage?.draw(in: bounds)
UIGraphicsPopContext()
}
}
如下所示:
當(dāng)滑動圖片,會發(fā)現(xiàn)CATiledLayer
載入小圖的時候會淡入到屏幕中敏释,這是CATiledLayer
的默認(rèn)行為库快,可以使用fadeDuration
屬性改變淡入時長或直接禁用掉。CATiledLayer
不同于大部分UIKit
和 Core Animation API钥顽,它支持多線程繪制义屏,draw(in:)
方法可能在多線程并行調(diào)用,需確保該方法內(nèi)的繪制代碼線程安全蜂大。
不要嘗試直接修改
CATiledLayer
的contents
屬性闽铐,因?yàn)檫@樣會禁用它的異步機(jī)制,使其和普通的CALayer
沒有區(qū)別奶浦。
7. CAEmitterLayer
CAEmitterLayer
是一個高性能的粒子引擎兄墅,用來創(chuàng)建實(shí)時粒子動畫。例如澳叉,煙霧隙咸、火沐悦、雨等。
CAEmitterLayer
是CAEmitterCell
實(shí)例的容器扎瓶,CAEmitterCell
定義了粒子效果所踊。創(chuàng)建一個或多個CAEmitterCell
對象作為不同類型粒子的模版,CAEmitterLayer
基于模版產(chǎn)生粒子流概荷。
CAEmitterCell
繼承自NSObject
,和CALayer
非常類似碌燕。CAEmitterCell
的contents
屬性可以定義為一個CGImage
误证,還有很多屬性用于配制粒子的外觀和行為。這里不會詳細(xì)介紹每一個屬性修壕,你可以在CAEmitterCell
文檔中查看詳細(xì)介紹愈捅。
下面創(chuàng)建擁有不同速度、透明度的粒子慈鸠,以視圖中心為emitterPosition
向四周發(fā)射的爆炸效果蓝谨。
// Create particle emitter layer
var replicatorLayer = CAReplicatorLayer()
emitter.position = view.layer.position
emitter.bounds = view.bounds
view.layer.addSublayer(emitter)
// Configure emitter
emitter.renderMode = .additive
emitter.emitterPosition = view.center
// Create a particle template
let cell = CAEmitterCell()
cell.contents = UIImage(named: "Spark")?.cgImage
cell.birthRate = 150
cell.lifetime = 5
cell.color = UIColor(red: 1.0, green: 0.5, blue: 0.1, alpha: 1.0).cgColor
cell.alphaSpeed = -0.4
cell.velocity = 50
cell.velocityRange = 50
cell.emissionRange = .pi * 2.0
// Add particle template to emitter
emitter.emitterCells = [cell]
如下所示:
CAEmitterCell
屬性可分為三類:
- 屬性初始值,如
color
屬性指定一個可以混合contents
圖片的顏色青团。在上述示例中譬巫,color
被設(shè)置為橘色。 - 屬性的變化范圍督笆。上述示例中芦昔,
emissionRange
被設(shè)置為360度,表示粒子可以向任意方向發(fā)射娃肿,粒子之間角度具有一定差值咕缎。可以通過設(shè)置一個小角度創(chuàng)建錐形效果料扰。 - 屬性隨時間的變化凭豪。上述示例中,
alphaSpeed
值為-0.4
,表示粒子的alpha
每秒減少0.4祭芦,創(chuàng)建一種粒子遠(yuǎn)離過程中逐漸消失的效果成榜。
CAEmitterLayer
屬性控制整個粒子系統(tǒng)的位置和形狀。CAEmitterLayer
的有些屬性與CAEmitterCell
屬性相同末早,設(shè)置CAEmitterLayer
的屬性后,會與CAEmitterCell
屬性相乘说庭。使用CAEmitterLayer
屬性可以控制整個粒子系統(tǒng)效果然磷。還有以下兩個重要屬性:
- preservesDepth:定義是否將粒子展平到平面中,默認(rèn)為
false
刊驴。如果為true
姿搜,則該圖層將其粒子渲染為位于該圖層上層的三維坐標(biāo)空間寡润。啟用后,layer 的filters
舅柜、backgroundFilters
和陰影相關(guān)屬性效果是未定義的梭纹。 - renderMode:控制粒子圖層在視覺上如何融合,默認(rèn)值為
unordered
致份。示例中使用additive
变抽,即重疊部分亮度增加。
像
CAEmitterLayer
的scale
氮块、seed
绍载、spin
等屬性乘數(shù),只影響新創(chuàng)建的粒子滔蝉,已經(jīng)發(fā)射出粒子不受影響击儡。例如,emitter 的scale
值為1蝠引,發(fā)射一些粒子后修改scale
為2阳谍。此時,已經(jīng)發(fā)射出去的粒子大小不受影響螃概,仍保持原來大小矫夯,新創(chuàng)建的粒子大小變?yōu)樵瓉矶丁?/p>
總結(jié)
這一部分介紹了多種圖層,以及使用這些圖層可以實(shí)現(xiàn)的效果谅年。像CATiledLayer
茧痒、CAEmitterLayer
等類都可以單獨(dú)寫成一篇文章,這里只作簡單介紹融蹂。另外旺订,CATextLayer
、CAMetaLayer
超燃、AVPlayerLayer
也是CALayer
的子類区拳,這篇文章并未介紹,可以自行查閱文檔意乓。
CALayer
并沒有針對所有情況都進(jìn)行性能優(yōu)化樱调。如果想要達(dá)到最佳性能,需根據(jù)需求選擇合適子類届良。下一篇文章CAAnimation:屬性動畫CABasicAnimation笆凌、CAKeyframeAnimation以及過渡動畫、動畫組將介紹顯式動畫士葫。
Demo名稱:CoreAnimation
源碼地址:https://github.com/pro648/BasicDemos-iOS/tree/master/CoreAnimation
上一篇:CGAffineTransform和CATransform3D
下一篇:CAAnimation:屬性動畫CABasicAnimation乞而、CAKeyframeAnimation以及過渡動畫、動畫組
參考資料:
歡迎更多指正:https://github.com/pro648/tips
本文地址:https://github.com/pro648/tips/blob/master/sources/CALayer及其各種子類.md