版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2020.07.10 星期五 |
前言
iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面钉跷,用戶交互也是通過UIKit進(jìn)行的宣蔚。感興趣的參考上面幾篇文章。
1. UIKit框架(一) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(一)
2. UIKit框架(二) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復(fù)使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復(fù)使用的滑塊(二)
7. UIKit框架(七) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(一)
8. UIKit框架(八) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(二)
11. UIKit框架(十一) —— UICollectionView的重用迄本、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用硕淑、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類似效果的實(shí)現(xiàn)(一)
21. UIKit框架(二十一) —— UIStackView的使用(一)
22. UIKit框架(二十二) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示(一)
23. UIKit框架(二十三) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示(二)
24. UIKit框架(二十四) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (一)
25. UIKit框架(二十五) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (二)
26. UIKit框架(二十六) —— UICollectionView的自定義布局 (一)
27. UIKit框架(二十七) —— UICollectionView的自定義布局 (二)
28. UIKit框架(二十八) —— 一個(gè)UISplitViewController的簡單實(shí)用示例 (一)
29. UIKit框架(二十九) —— 一個(gè)UISplitViewController的簡單實(shí)用示例 (二)
30. UIKit框架(三十) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡單示例(一)
31. UIKit框架(三十一) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡單示例(二)
32. UIKit框架(三十二) —— 替換Peek and Pop交互的基于iOS13的Context Menus(一)
33. UIKit框架(三十三) —— 替換Peek and Pop交互的基于iOS13的Context Menus(二)
34. UIKit框架(三十四) —— Accessibility的使用(一)
35. UIKit框架(三十五) —— Accessibility的使用(二)
36. UIKit框架(三十六) —— UICollectionView UICollectionViewDiffableDataSource的使用(一)
37. UIKit框架(三十七) —— UICollectionView UICollectionViewDiffableDataSource的使用(二)
38. UIKit框架(三十八) —— 基于CollectionView轉(zhuǎn)盤效果的實(shí)現(xiàn)(一)
39. UIKit框架(三十九) —— iOS 13中UISearchController 和 UISearchBar的新更改(一)
40. UIKit框架(四十) —— iOS 13中UISearchController 和 UISearchBar的新更改(二)
41. UIKit框架(四十一) —— 使用協(xié)議構(gòu)建自定義Collection(一)
42. UIKit框架(四十二) —— 使用協(xié)議構(gòu)建自定義Collection(二)
開始
首先看下主要內(nèi)容:
在本文中,您將了解CALayer及其工作原理嘉赎。 您將使用CALayer以獲得酷炫的效果置媳,例如形狀,漸變和粒子系統(tǒng)公条。本文內(nèi)容來自翻譯拇囊。
接著看一下寫作環(huán)境:
Swift 5, iOS 13, Xcode 11
下面就是正文了
您可能知道,在iOS應(yīng)用中看到的所有內(nèi)容都是視圖靶橱。有按鈕視圖寂拆,表格視圖,滑塊視圖抓韩,甚至包含其他視圖的父視圖纠永!
但是您可能不知道,iOS中的每個(gè)視圖都由另一個(gè)稱為圖層的類(具體來說就是CALayer
)支持谒拴。
在本文中尝江,您將構(gòu)建Layer Player
應(yīng)用程序。在此過程中英上,您將學(xué)到:
- 什么是
CALayer
及其運(yùn)作方式炭序。 - 如何使用
CALayer
功能來實(shí)現(xiàn)酷效果,例如形狀苍日,漸變甚至粒子系統(tǒng)惭聂。
CALayer
具有多種屬性和方法可以修改。它具有幾個(gè)具有獨(dú)特屬性和方法的子類相恃。
Layer Player
應(yīng)用程序演示了九種不同的CALayer
功能辜纲。
入門項(xiàng)目并沒有做什么用。您將要編寫代碼以將此應(yīng)用程序變成功能齊全的CALayer
指導(dǎo)!
在每個(gè)部分中耕腾,您都將添加必要的代碼以使神奇的圖層發(fā)揮作用见剩。 添加了每一行代碼后,請(qǐng)按照剛剛啟用的設(shè)置進(jìn)行操作扫俺。 這將使您對(duì)所探索的每種功能的功能有更深入的了解苍苞。
但是首先,來一些理論狼纬。
How does CALayer relate to UIView?
UIView
處理許多事情羹呵,包括布局和觸摸事件。 但是疗琉,它不能直接控制圖形或動(dòng)畫担巩。 UIKit
將該任務(wù)委托給Core Animation
框架,從而可以使用CALayer
没炒。 實(shí)際上涛癌,UIView
只是CALayer
的封裝。
每個(gè)UIView
都有一個(gè)根CALayer
送火,可以包含多個(gè)子層拳话。 當(dāng)您在UIView
上設(shè)置bounds
時(shí),該視圖又在其支持CALayer
上設(shè)置bounds
种吸。 如果在UIView
上調(diào)用layoutIfNeeded()
弃衍,則該調(diào)用將轉(zhuǎn)發(fā)到根CALayer
。
在深入研究Layer Player
應(yīng)用程序之前坚俗,還應(yīng)該了解一些有關(guān)CALayer
的知識(shí):
- Layers can have sublayers - 層可以具有子層:就像視圖可以具有子視圖一樣镜盯,層也可以具有子層。 您可以將它們用于一些很酷的效果猖败!
-
Their properties are animatable - 它們的屬性是可設(shè)置動(dòng)畫的:更改圖層的屬性時(shí)速缆,可以使用
CAAnimation
為更改設(shè)置動(dòng)畫。 - Layers are lightweight - 圖層重量輕:圖層的重量比視圖輕恩闻,因此可以幫助您獲得更好的性能艺糜。
- They have tons of useful properties - 它們具有大量有用的屬性:您將在以下示例中進(jìn)行探索。
現(xiàn)在幢尚,您就可以開始使用CALayer
創(chuàng)建一些自定義視圖了破停。
Customizing Views With CALayer
打開CALayerViewController.swift
并將以下代碼添加到setupLayer()
中:
//1
layer.frame = viewForLayer.bounds
layer.contents = UIImage(named: "star")?.cgImage
// 2
layer.contentsGravity = .center
layer.magnificationFilter = .linear
// 3
layer.cornerRadius = 100.0
layer.borderWidth = 12.0
layer.borderColor = UIColor.white.cgColor
layer.backgroundColor = swiftOrangeColor.cgColor
//4
layer.shadowOpacity = 0.75
layer.shadowOffset = CGSize(width: 0, height: 3)
layer.shadowRadius = 3.0
layer.isGeometryFlipped = false
在此代碼中,您將創(chuàng)建一個(gè)自定義視圖:
- 1)設(shè)置圖層
layer
的邊界bounds
尉剩,然后將圖像設(shè)置為圖層的內(nèi)容真慢。 注意底層CGImage
的使用。 - 2)然后理茎,將圖像居中放置在圖層中黑界。 您可以使用
contentsGravity
來更改大泄苕摇(如resizing, resizing aspect and resizing aspect fill
)以及位置(中心,頂部园爷,右上角,右邊等)式撼。magnificationFilter
控制放大圖像的行為童社。 - 3)接下來,設(shè)置
CALayer
的背景顏色著隆,使其變圓并為其添加邊框扰楼。 請(qǐng)注意,您正在使用基礎(chǔ)CGColor
對(duì)象更改圖層的顏色屬性美浦。 - 4)最后弦赖,為圖層創(chuàng)建陰影。 當(dāng)
isGeometryFlipped
為true
時(shí)浦辨,位置幾何形狀和陰影將上下顛倒蹬竖。
構(gòu)建并運(yùn)行。 選擇CALayer
流酬,然后檢查結(jié)果:
控件目前不執(zhí)行任何操作币厕。 因此,添加以下內(nèi)容以到prepare(for:sender:)
:
if segue.identifier == "DisplayLayerControls" {
(segue.destination as? CALayerControlsViewController)?.layerViewController = self
}
這將連接嵌入式CALayerControlsViewController
芽腾。 再次構(gòu)建并運(yùn)行旦装,然后檢查實(shí)際使用的圖層屬性。 試玩各種控件摊滔,以感受一下使用CALayer
可以做什么阴绢!
1. Improving Performance With ShouldRasterize and DrawsAsynchronously
CALayer
具有兩個(gè)其他可改善性能的屬性:shouldRasterize
和drawsAsynchronously
。
默認(rèn)情況下艰躺,shouldRasterize
為false
呻袭。設(shè)置為true
時(shí),圖層的內(nèi)容僅渲染一次腺兴,從而提高了性能棒妨。非常適合在屏幕上動(dòng)起來但外觀不變的對(duì)象。
drawsAsynchronously
與shouldRasterize
相反含长,默認(rèn)情況下也為false
券腔。當(dāng)應(yīng)用需要重復(fù)重繪圖層內(nèi)容時(shí),將其設(shè)置為true
可以提高性能拘泞。例如纷纫,當(dāng)您使用連續(xù)渲染動(dòng)畫粒子的發(fā)射器層時(shí),可能會(huì)發(fā)生這種情況陪腌。您將在本教程的后面部分中使用此功能辱魁。
注意:在設(shè)置
shouldRasterize
或drawsAsynchronously
之前烟瞧,請(qǐng)先考慮其含義。更改設(shè)置并比較性能染簇。這將幫助您確定在給定情況下激活這些功能是否實(shí)際上會(huì)提高性能参滴。如果您濫用這些屬性,性能可能會(huì)降低锻弓!
Scrolling With CAScrollLayer
CAScrollLayer
顯示可滾動(dòng)圖層的一部分砾赔。 這是非常基本的-它無法直接響應(yīng)用戶的觸摸青灼,甚至無法檢查可滾動(dòng)圖層的bounds
暴心。 但這確實(shí)很酷,例如防止?jié)L動(dòng)超出bounds
杂拨。
UIScrollView
不使用CAScrollLayer
來完成其工作专普。 而是直接更改圖層的bounds
。 使用CAScrollLayer
弹沽,您可以:
- 將滾動(dòng)模式設(shè)置為水平或垂直
(horizontal or vertical)
檀夹。 - 以編程方式滾動(dòng)到特定點(diǎn)
point
或區(qū)域area
。
構(gòu)建并運(yùn)行策橘,然后從菜單中選擇CAScrollLayer
击胜。 您會(huì)看到一張圖片和兩個(gè)控制滾動(dòng)方向的開關(guān)。
現(xiàn)在是時(shí)候設(shè)置滾動(dòng)了役纹。
1. Setting up Scrolling
返回代碼并打開CAScrollLayerViewController.swift
偶摔。 視圖中已經(jīng)有一個(gè)CAScrollLayer
。
將以下內(nèi)容添加到panRecognized(_ :)
:
var newPoint = scrollingView.bounds.origin
newPoint.x -= sender.translation(in: scrollingView).x
newPoint.y -= sender.translation(in: scrollingView).y
sender.setTranslation(.zero, in: scrollingView)
scrollingViewLayer.scroll(to: newPoint)
if sender.state == .ended {
UIView.animate(withDuration: 0.3) {
self.scrollingViewLayer.scroll(to: CGPoint.zero)
}
}
發(fā)生平移手勢(shì)時(shí)促脉,您需要計(jì)算所需的相應(yīng)平移辰斋,然后在CAScrollLayer
上調(diào)用scroll(to :)
方法以相應(yīng)地移動(dòng)圖像。
scroll(to :)
不會(huì)自動(dòng)設(shè)置動(dòng)畫瘸味,因此您可以使用UIView.animate(withDuration:animations :)
對(duì)其進(jìn)行明確設(shè)置宫仗。
構(gòu)建并運(yùn)行,然后返回到CAScrollLayer
示例旁仿。 現(xiàn)在藕夫,平移圖像時(shí),您將看到類似以下的內(nèi)容:
Layer Player
還包括兩個(gè)控件枯冈,用于鎖定水平和垂直滾動(dòng)毅贮。 接下來,您將看一下這部分尘奏。
2. Locking Scrolling Directions
將以下代碼添加到scrollingSwitchChanged(_ :)
:
switch (horizontalScrollingSwitch.isOn, verticalScrollingSwitch.isOn) {
case (true, true):
scrollingViewLayer.scrollMode = .both
case (true, false):
scrollingViewLayer.scrollMode = .horizontally
case (false, true):
scrollingViewLayer.scrollMode = .vertically
default:
scrollingViewLayer.scrollMode = .none
}
在這里滩褥,您添加了一個(gè)簡單的switch
塊。 它根據(jù)用戶界面中開關(guān)的值確定滾動(dòng)方向炫加。
現(xiàn)在構(gòu)建并運(yùn)行瑰煎。 返回應(yīng)用程序铺然,撥動(dòng)開關(guān),然后查看CAScrollLayer
的行為酒甸。
以下是何時(shí)使用或不使用CAScrollLayer
的一些經(jīng)驗(yàn)法則:
- 如果您想要輕巧
(lightweight)
的東西并且只需要以編程方式滾動(dòng)魄健,請(qǐng)考慮使用CAScrollLayer
。 - 如果希望用戶能夠滾動(dòng)插勤,最好使用
UIScrollView
沽瘦。 要了解更多信息,請(qǐng)查看我們的Scroll View School視頻教程系列饮六。 - 如果要滾動(dòng)很大的圖像其垄,請(qǐng)考慮使用
CATiledLayer
苛蒲。
Rendering Text With CATextLayer
CATextLayer
提供簡單但快速的純文本或?qū)傩宰址秩尽?與UILabel
不同卤橄,CATextLayer
不能具有分配的UIFont
,只能具有CTFont
或CGFont
臂外。
打開CATextLayerViewController.swift
并將以下內(nèi)容添加到setUpTextLayer()
的末尾:
// 1
textLayer.font = helveticaFont
textLayer.fontSize = Constants.baseFontSize
// 2
textLayer.foregroundColor = UIColor.darkGray.cgColor
textLayer.isWrapped = true
textLayer.alignmentMode = .left
textLayer.truncationMode = .end
// 3
textLayer.contentsScale = UIScreen.main.scale
這是您正在做的事情:
- 1) 您設(shè)置文本圖層的字體窟扑。請(qǐng)注意,這是
CTFont
漏健,而不是UIFont
嚎货。您可以使用CTFontCreateWithName(_:_:_ :)
創(chuàng)建這些文件。CATextLayer
允許您像在此處一樣直接在圖層上設(shè)置字體大小蔫浆。 - 2) 接下來殖属,設(shè)置文本顏色,換行瓦盛,對(duì)齊和截?cái)嗄J较聪浴K羞@些都可以在常規(guī)
UILabel
或UITextView
上獲得。 - 3) 最后原环,將圖層的
contentsScale
設(shè)置為與屏幕的比例相匹配挠唆。默認(rèn)情況下,所有圖層類(不僅是CATextLayer
)都以比例因子1
進(jìn)行渲染嘱吗。將圖層附加到視圖會(huì)自動(dòng)將其contentScale
設(shè)置為當(dāng)前屏幕的適當(dāng)比例因子玄组。但是,對(duì)于您手動(dòng)創(chuàng)建的任何圖層谒麦,必須顯式設(shè)置contentsScale
俄讹。否則,其比例因子將為1
绕德,從而使其在Retina
顯示器上顯示為像素化颅悉。
構(gòu)建并運(yùn)行,然后從菜單中選擇CATextLayer
迁匠。 Layer Player
具有可以更改許多CATextLayer
屬性的控件剩瓶。和他們一起玩驹溃,看看他們做什么:
接下來,您將使Layer Player
能夠播放媒體文件延曙。
Playing Media With AVPlayerLayer
AVPlayerLayer
為AVFoundation
增添了美好的一面豌鹤。 它擁有一個(gè)AVPlayer
來播放AVPlayerItem
類型的媒體文件。
1. Setting up Media Playback
打開AVPlayerLayerViewController.swift
并將以下代碼添加到setUpPlayerLayer()
中:
// 1
playerLayer.frame = viewForPlayerLayer.bounds
// 2
let url = Bundle.main.url(forResource: "colorfulStreak", withExtension: "m4v")!
let item = AVPlayerItem(asset: AVAsset(url: url))
let player = AVPlayer(playerItem: item)
// 3
player.actionAtItemEnd = .none
// 4
player.volume = 1.0
player.rate = 1.0
playerLayer.player = player
在此代碼中枝缔,您設(shè)置了播放器布疙。這是如何做:
- 1) 首先,設(shè)置圖層的
frame
愿卸。 - 2) 接下來灵临,使用
AVPlayerItem
創(chuàng)建一個(gè)player
。 - 3) 您告訴播放器完成播放后什么也不做趴荸。其他選項(xiàng)包括暫腿甯龋或前進(jìn)到下一個(gè)資源(如果適用)。
- 4) 最后发钝,設(shè)置播放器的音量和速率顿涣。
現(xiàn)在您可以播放媒體文件了,您將使用戶能夠更改他們的播放速度酝豪。
2. Changing Playback Speeds
rate
設(shè)置視頻播放速度涛碑。 0
表示暫停,1
表示視頻以正常速度播放孵淘。
但是蒲障,設(shè)置速率rate
也會(huì)指示以該速率開始播放。換句話說瘫证,調(diào)用pause()
并將rate
設(shè)置為0
作用是一樣的揉阎,同樣調(diào)用play()
并將rate
設(shè)置為1
作用也是一樣!
那么快進(jìn)痛悯,慢動(dòng)作或反向播放呢余黎?好吧,AVPlayer
都可以滿足您载萌!
當(dāng)您將rate
設(shè)置為高于1
的任何值時(shí)惧财,播放將以該速度乘以常規(guī)速度開始。例如扭仁,將rate
設(shè)置為2
表示倍速垮衷。并將rate
設(shè)置為負(fù)數(shù)會(huì)導(dǎo)致以該速度乘以正常速度反向播放。
但是乖坠,在以常規(guī)速度向前播放以外的任何速率進(jìn)行播放之前搀突,應(yīng)檢查AVPlayerItem
中的相應(yīng)變量以驗(yàn)證是否可以該速率播放:
-
canPlayFastForward
大于1
的任何數(shù)字。 -
canPlaySlowForward
的范圍為0
到最大(但不包括1
)之間的任何數(shù)字熊泵。 -
canPlayReverse
為-1
仰迁。 -
canPlaySlowReverse
的范圍是-1
到最大(但不包括0
)之間的任何數(shù)字甸昏。 -
canPlayFastReverse
的值小于-1
。
大多數(shù)視頻可以以各種前進(jìn)速度播放徐许,但很少可以反向播放施蜜。
3. Updating the User Interface
現(xiàn)在,回到代碼雌隅。當(dāng)您點(diǎn)擊播放按鈕時(shí)翻默,它應(yīng)切換控件以播放AVAset
并設(shè)置按鈕的標(biāo)題。
將以下內(nèi)容添加到playButtonTapped(_ :)
:
if player?.rate == 0 {
player?.rate = rate
updatePlayButtonTitle(isPlaying: true)
} else {
player?.pause()
updatePlayButtonTitle(isPlaying: false)
}
在此恰起,您可以根據(jù)初始速率切換播放器的狀態(tài)并更新播放按鈕的標(biāo)題修械。
最后,您將添加代碼检盼,以在播放器到達(dá)媒體文件的末尾時(shí)將播放光標(biāo)移回開頭肯污。
4. Resetting the Playback Cursor
在viewDidLoad()
中,您可以看到AVPlayerItemDidPlayToEndTimeNotification
具有observer
梯皿。 當(dāng)AVPlayerItem
到達(dá)末尾時(shí)仇箱,將調(diào)用此通知县恕。
將以下代碼添加到playerDidReachEndNotificationHandler(_ :)
:
// 1
guard let playerItem = notification.object as? AVPlayerItem else { return }
// 2
playerItem.seek(to: .zero, completionHandler: nil)
// 3
if player?.actionAtItemEnd == .pause {
player?.pause()
updatePlayButtonTitle(isPlaying: false)
}
在此代碼中:
- 1) 您驗(yàn)證通知對(duì)象是
AVPlayerItem
东羹。 - 2) 您可以使用
seek(to:completionHandler :)
將播放器發(fā)送到所需位置吨述。 在這種情況下钾菊,您將播放器發(fā)送到CMTime.zero
這是開始枚粘。 - 3) 如果播放器的
actionAtItemEnd
設(shè)置為.pause
苇羡,則可以暫停播放器谣光,并相應(yīng)地設(shè)置按鈕文本罩锐。
構(gòu)建并運(yùn)行侦高,然后從菜單中選擇AVPlayerLayer
停巷。 更改控件上的值师坎,以查看每個(gè)控件如何更改圖層的行為恕酸。
下一步,您將看到使用CALayer
制作炫酷漸變非常容易胯陋。
Color Blending With CAGradientLayer
CAGradientLayer
使混合兩種或多種顏色變得容易蕊温,這使其特別適合于背景。您可以通過分配以下內(nèi)容進(jìn)行配置:
-
CGColors
數(shù)組遏乔。 - 一個(gè)開始點(diǎn)
startPoint
义矛,用于指定漸變圖層應(yīng)從何處開始。 - 一個(gè)
Endpoint
盟萨,用于指定漸變層應(yīng)在何處結(jié)束凉翻。
請(qǐng)記住,startPoint
和endPoint
不是顯式點(diǎn)捻激。而是在單位坐標(biāo)空間中定義它們制轰,并在繪制它們時(shí)將它們映射到圖層的邊界前计。換一種說法:
-
x
值為1
表示該點(diǎn)位于圖層的右邊緣。 -
y
值為1
表示該點(diǎn)位于圖層的底部邊緣垃杖。
CAGradientLayer
具有type
屬性残炮,可用于更改漸變圖案。默認(rèn)(也是最常用的)是axial
(線性)缩滨。這意味著势就,如果在startPoint
和endPoint
之間繪制一條線(A)
,則漸變將沿著垂直于A
的假想線(B)
發(fā)生脉漏,并且B
上的所有點(diǎn)都將具有相同的顏色:
或者苞冯,您可以使用locations
屬性控制漸變圖案。 location
接受一個(gè)介于0
到1
之間的值的數(shù)組侧巨。這些值指定相對(duì)停止點(diǎn)舅锄,漸變層應(yīng)在其中使用colors
數(shù)組中的下一個(gè)顏色。 如果未指定司忱,則默認(rèn)情況下停止位置的間隔均勻皇忿。
注意:如果設(shè)置
locations
,則其數(shù)量必須與colors
的數(shù)量匹配坦仍,否則會(huì)發(fā)生不良情況鳍烁。 所以要當(dāng)心!
打開CAGradientLayerViewController.swift
并將以下代碼添加到setUpGradientLayer()
中:
gradientLayer.frame = viewForGradientLayer.bounds
gradientLayer.colors = colors
gradientLayer.locations = locations.map { NSNumber(value: $0) }
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
在此代碼中繁扎,您為圖層分配了一個(gè)顏色數(shù)組幔荒,并設(shè)置了起點(diǎn)和終點(diǎn)。
構(gòu)建并運(yùn)行梳玫,從菜單中選擇CAGradientLayer
爹梁,然后查看結(jié)果:
好豐富多彩! Layer Player
為您提供了更改起點(diǎn)和終點(diǎn)提澎,顏色和位置的控件姚垃。 嘗試他們的樂趣,看看您能得到什么盼忌。
對(duì)于下一步积糯,您將向Layer Player
添加加載動(dòng)畫。
Creating a Loading Animation with CAReplicatorLayer
CAReplicatorLayer
將圖層復(fù)制指定的次數(shù)碴犬。 這使您可以創(chuàng)建一些令人驚訝的炫酷效果絮宁!
每個(gè)圖層副本可以具有自己的顏色和位置更改。 您可以延遲其繪制服协,以使整個(gè)復(fù)制器層具有動(dòng)畫效果绍昂。
構(gòu)建并運(yùn)行,然后從菜單中選擇CAReplicatorLayer
。 您會(huì)看到幾個(gè)控件……但沒有什么可控制:
首先窘游,配置要復(fù)制的圖層唠椭。
1. Configuring Replicator Layers
返回Xcode并打開CAReplicatorLayerViewController.swift
。 在// MARK: - Layer setup
下有三種方法要填充忍饰。
首先贪嫂,將以下內(nèi)容添加到setUpReplicatorLayer()
中:
// 1
replicatorLayer.frame = viewForReplicatorLayer.bounds
// 2
let count = instanceCountSlider.value
replicatorLayer.instanceCount = Int(count)
replicatorLayer.instanceDelay =
CFTimeInterval(instanceDelaySlider.value / count)
// 3
replicatorLayer.instanceColor = UIColor.white.cgColor
replicatorLayer.instanceRedOffset = offsetValueForSwitch(offsetRedSwitch)
replicatorLayer.instanceGreenOffset = offsetValueForSwitch(offsetGreenSwitch)
replicatorLayer.instanceBlueOffset = offsetValueForSwitch(offsetBlueSwitch)
replicatorLayer.instanceAlphaOffset = offsetValueForSwitch(offsetAlphaSwitch)
//4
let angle = Float.pi * 2.0 / count
replicatorLayer.instanceTransform =
CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0)
//5
viewForReplicatorLayer.layer.addSublayer(replicatorLayer)
在此代碼中,配置復(fù)制圖層(replicator layer)
的實(shí)例:
- 1) 首先艾蓝,設(shè)置圖層的
frame
力崇。 - 2) 您可以設(shè)置要?jiǎng)?chuàng)建的復(fù)制數(shù)量以及兩次創(chuàng)建之間的時(shí)間延遲。
- 3) 您可以定義所有復(fù)制實(shí)例的基礎(chǔ)顏色以及要添加到每個(gè)顏色組件的增量值赢织。 每個(gè)默認(rèn)值均為0亮靴,可有效保留所有實(shí)例的顏色值。 但是于置,在這種情況下茧吊,實(shí)例顏色最初設(shè)置為白色。 這意味著紅色八毯,綠色和藍(lán)色已經(jīng)是1.0搓侄。 例如,如果將紅色設(shè)置為0话速,并將綠色和藍(lán)色設(shè)置為負(fù)數(shù)讶踪,則紅色將成為突出的顏色。 同樣尿孔,將
alpha
偏移量添加到每個(gè)連續(xù)復(fù)制實(shí)例的alpha
中俊柔。 - 4) 現(xiàn)在筹麸,旋轉(zhuǎn)每個(gè)實(shí)例以創(chuàng)建一個(gè)圓形效果活合。
- 5) 最后,將圖層添加到視圖的圖層物赶。
2. Setting Position and Fade
接下來白指,為replicator layer
創(chuàng)建一個(gè)實(shí)例層以供使用。 將以下內(nèi)容添加到setUpInstanceLayer
:
let layerWidth = CGFloat(layerSizeSlider.value)
let midX = viewForReplicatorLayer.bounds.midX - layerWidth / 2.0
instanceLayer.frame = CGRect(
x: midX,
y: 0.0,
width: layerWidth,
height: layerWidth * lengthMultiplier)
instanceLayer.backgroundColor = UIColor.white.cgColor
replicatorLayer.addSublayer(instanceLayer)
此代碼設(shè)置實(shí)例frame
酵紫。 在這里告嘲,第一個(gè)實(shí)例將繪制在中心x
和viewForReplicatorLayer
的bounds
的頂部。 然后奖地,您設(shè)置實(shí)例的顏色并將實(shí)例層添加到replicator layer
橄唬。
現(xiàn)在用于淡入淡出動(dòng)畫。 將以下內(nèi)容添加到setUpLayerFadeAnimation
中:
fadeAnimation.fromValue = 1.0
fadeAnimation.toValue = 0.0
fadeAnimation.repeatCount = Float(Int.max)
在這里参歹,您使用CABasicAnimation
的fadeAnimation
將實(shí)例的不透明度從1
(不透明)更改為0
(透明)仰楚。
構(gòu)建并運(yùn)行并享受您的代碼現(xiàn)在所做的工作:
Layer Player
包含用于操縱大多數(shù)這些屬性的控件。 更改值,看看它們?nèi)绾斡绊憚?dòng)畫僧界!
現(xiàn)在侨嘀,您已經(jīng)創(chuàng)建了一個(gè)有趣的動(dòng)畫圓,接下來將使用CALayer
的另一個(gè)屬性繪制星星捂襟。
Drawing a Star With CAShapeLayer
CAShapeLayer
使用可縮放的矢量路徑繪制線條咬腕,形狀和圖案-比使用圖片要快得多! 另一個(gè)好處是葬荷,您無需提供常規(guī)的@ 2x
和@ 3x
尺寸的圖像涨共。
此外,您還可以使用各種屬性來自定義圖形宠漩。 例如煞赢,您可以調(diào)整線的粗細(xì),顏色哄孤,虛線并指定線的連接方式照筑。 而且,當(dāng)您的線條形成形狀時(shí)瘦陈,您可以更改其填充方式凝危。
現(xiàn)在該畫一個(gè)橙色的星星了! 首先晨逝,打開CAShapeLayerViewController.swift
并將以下內(nèi)容添加到setUpShapeLayer()
中:
// 1
shapeLayer.path = openPath.cgPath
// 2
shapeLayer.lineCap = .butt
shapeLayer.lineJoin = .miter
shapeLayer.miterLimit = 4.0
// 3
shapeLayer.lineWidth = CGFloat(lineWidthSlider.value)
shapeLayer.strokeColor = swiftOrangeColor.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
// 4
shapeLayer.lineDashPattern = nil
shapeLayer.lineDashPhase = 0.0
viewForShapeLayer.layer.addSublayer(shapeLayer)
經(jīng)歷這個(gè):
- 1)
CAShapeLayer
采用CGPath
蛾默,它定義了如何在屏幕上繪制它。 您很快就會(huì)畫出這條路捉貌。 - 2)
lineJoin
和lineCap
定義路徑中的線如何相交和結(jié)束支鸡。 - 3) 設(shè)置路徑線的寬度和顏色。
- 4)
lineDashPattern
和lineDashPhase
允許您繪制虛線(dashed lines)
趁窃。 在這種情況下牧挣,您將繪制不帶dashes
的簡單線條。
接下來醒陆,您將繪制路徑本身瀑构。 將以下內(nèi)容添加到setUpPath()
中:
openPath.move(to: CGPoint(x: 30, y: 196))
openPath.addCurve(
to: CGPoint(x: 112.0, y: 12.5),
controlPoint1: CGPoint(x: 110.56, y: 13.79),
controlPoint2: CGPoint(x: 112.07, y: 13.01))
openPath.addCurve(
to: CGPoint(x: 194, y: 196),
controlPoint1: CGPoint(x: 111.9, y: 11.81),
controlPoint2: CGPoint(x: 194, y: 196))
openPath.addLine(to: CGPoint(x: 30.0, y: 85.68))
openPath.addLine(to: CGPoint(x: 194.0, y: 48.91))
openPath.addLine(to: CGPoint(x: 30, y: 196))
這將繪制您的星形。
構(gòu)建并運(yùn)行刨摩,然后選擇CAShapeLayer
以查看結(jié)果:
Layer Player
包含用于操縱許多CAShapeLayer
屬性的控件寺晌。 玩這些控件來調(diào)整星星:
CALayer
不僅可以讓您繪制2D
圖形,還可以繪制3D
形狀澡刹。 這就是您在下一節(jié)中要做的呻征。
Drawing a 3D Cube With CATransformLayer
CATransformLayer
不會(huì)像其他圖層類一樣展平其子圖層層次結(jié)構(gòu)。 這使得繪制3D結(jié)構(gòu)非常方便罢浇。 CATransformLayer
實(shí)際上是其子層的容器陆赋。 每個(gè)子層可以具有自己的transforms
和opacity
更改边篮。 但是,它忽略對(duì)其他渲染圖層屬性(如邊框?qū)挾群皖伾┑母摹?/p>
在本部分中奏甫,您將構(gòu)建一個(gè)交互式3D
立方體戈轿。 首先打開CATransformLayerViewController.swift
并將以下代碼添加到buildCube()
中:
// 1
transformLayer = CATransformLayer()
// 2
let redLayer = sideLayer(color: redColor)
redLayer.addSublayer(swipeMeTextLayer)
transformLayer.addSublayer(redLayer)
// 3
let orangeLayer = sideLayer(color: orangeColor)
var orangeTransform = CATransform3DMakeTranslation(
sideLength / 2.0,
0.0,
sideLength / -2.0)
orangeTransform = CATransform3DRotate(
orangeTransform,
degreesToRadians(90.0),
0.0,
1.0,
0.0)
orangeLayer.transform = orangeTransform
transformLayer.addSublayer(orangeLayer)
在這里,您創(chuàng)建cube
的前兩個(gè)側(cè)面:
- 1) 首先阵子,創(chuàng)建一個(gè)
CATransformerLayer
思杯。 - 2) 接下來,添加一個(gè)
CALayer
來表示cube的紅色面挠进,并將其添加到
transformLayer`色乾。 - 3) 然后,添加
cube的橙色面领突。 您可以通過設(shè)置
transform屬性來定位它暖璧,該屬性接受
CATransform3D`。
同樣君旦,添加以下代碼:
let yellowLayer = sideLayer(color: yellowColor)
yellowLayer.transform = CATransform3DMakeTranslation(0.0, 0.0, -sideLength)
transformLayer.addSublayer(yellowLayer)
let greenLayer = sideLayer(color: greenColor)
var greenTransform = CATransform3DMakeTranslation(
sideLength / -2.0,
0.0,
sideLength / -2.0)
greenTransform = CATransform3DRotate(
greenTransform,
degreesToRadians(90.0),
0.0,
1.0,
0.0)
greenLayer.transform = greenTransform
transformLayer.addSublayer(greenLayer)
let blueLayer = sideLayer(color: blueColor)
var blueTransform = CATransform3DMakeTranslation(
0.0,
sideLength / -2.0,
sideLength / -2.0)
blueTransform = CATransform3DRotate(
blueTransform,
degreesToRadians(90.0),
1.0,
0.0,
0.0)
blueLayer.transform = blueTransform
transformLayer.addSublayer(blueLayer)
let purpleLayer = sideLayer(color: purpleColor)
var purpleTransform = CATransform3DMakeTranslation(
0.0,
sideLength / 2.0,
sideLength / -2.0)
purpleTransform = CATransform3DRotate(
purpleTransform,
degreesToRadians(90.0),
1.0,
0.0,
0.0)
purpleLayer.transform = purpleTransform
transformLayer.addSublayer(purpleLayer)
在這里澎办,創(chuàng)建cube
的其余四個(gè)面。
最后金砍,設(shè)置圖層的z
錨點(diǎn)局蚀,然后通過添加以下內(nèi)容將其添加到屏幕上:
transformLayer.anchorPointZ = sideLength / -2.0
viewForTransformLayer.layer.addSublayer(transformLayer)
在這里,您可以配置anchorPointZ
恕稠,以指定發(fā)生幾何操作的z
軸上的錨點(diǎn)琅绅。
注意:要了解有關(guān)矩陣變換的更多信息,請(qǐng)查看以下練習(xí):
- Rich Turton 的 3DTransformFun project項(xiàng)目鹅巍。
- Enter The Matrix project 的
Matrix
項(xiàng)目千扶。
現(xiàn)在,您已經(jīng)創(chuàng)建了cube
骆捧,是時(shí)候設(shè)置它了澎羞。
1. Rotating the Cube
要旋轉(zhuǎn)cube
,您需要處理觸摸事件凑懂。 您無法直接點(diǎn)擊hit test
變換圖層(transform layer)
煤痕,因?yàn)樗鼪]有2D
坐標(biāo)空間可用于映射接觸點(diǎn)。 但是接谨,可以對(duì)各個(gè)子層進(jìn)行測試。
該項(xiàng)目代碼已經(jīng)包括Bill Dudney
的 TrackBall utility實(shí)用程序塘匣,該實(shí)用程序已移植到Swift
脓豪。 這使基于用戶手勢(shì)的3D transform
變得容易。 您可以在// MARK: - Touch Handling
下check it out
忌卤。
構(gòu)建并運(yùn)行扫夜。 從菜單中選擇CATransformLayer
,您會(huì)看到一個(gè)紅色正方形:
滑動(dòng)cube
并切換開關(guān)以查看它們?nèi)绾胃?code>cube:
Making a Shooting Star With CAEmitterLayer
在計(jì)算機(jī)圖形學(xué)中,粒子系統(tǒng)Particle Systems用于生成現(xiàn)實(shí)世界的現(xiàn)象笤闯,例如火堕阔,煙,火花颗味,煙花和爆炸超陆。
在Core Animation
中,CAEmitterLayer
可用于渲染此類系統(tǒng)并控制作為CAEmitterCell
實(shí)例的動(dòng)畫粒子浦马。 CAEmitterLayer
和CAEmitterCell
都具有更改渲染速率时呀,大小,形狀晶默,顏色谨娜,速度,壽命等的屬性磺陡。
1. Preparing the Emitter Layer
發(fā)射層配置發(fā)射粒子的位置和形狀趴梢。
將以下內(nèi)容添加到CAEmitterLayerViewController.swift
中的setUpEmitterLayer()
中:
// 1
resetEmitterCells()
emitterLayer.frame = viewForEmitterLayer.bounds
viewForEmitterLayer.layer.addSublayer(emitterLayer)
// 2
emitterLayer.seed = UInt32(Date().timeIntervalSince1970)
// 3
emitterLayer.emitterPosition = CGPoint(
x: viewForEmitterLayer.bounds.midX * 1.5,
y: viewForEmitterLayer.bounds.midY)
// 4
emitterLayer.renderMode = .additive
這是您所做的:
- 1) 首先,重置圖層并將其添加到視圖中币他。
- 2) 然后垢油,為該層的隨機(jī)數(shù)生成器提供種子。 反過來圆丹,這會(huì)隨機(jī)化層的發(fā)射器單元的某些屬性滩愁,例如速度。 有關(guān)更多信息辫封,請(qǐng)參見下一個(gè)代碼塊之后的以下注釋硝枉。
- 3) 您設(shè)置發(fā)射器位置。
- 4) 最后倦微,定義粒子單元如何渲染到圖層中妻味。
2. Setting up the Emitter Cell
接下來,設(shè)置發(fā)射器單元(emitter cell)
欣福,該單元確定粒子的特定行為和外觀责球。
將以下內(nèi)容添加到setUpEmitterCell()
中:
// 1
emitterCell.contents = UIImage(named: "smallStar")?.cgImage
// 2
emitterCell.velocity = 50.0
emitterCell.velocityRange = 500.0
// 3
emitterCell.color = UIColor.black.cgColor
// 4
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
emitterCell.scaleSpeed = 0.1
// 5
let zeroDegreesInRadians = degreesToRadians(0.0)
emitterCell.spin = degreesToRadians(130.0)
emitterCell.spinRange = zeroDegreesInRadians
emitterCell.emissionLatitude = zeroDegreesInRadians
emitterCell.emissionLongitude = zeroDegreesInRadians
emitterCell.emissionRange = degreesToRadians(360.0)
// 6
emitterCell.lifetime = 1.0
emitterCell.birthRate = 250.0
// 7
emitterCell.xAcceleration = -800
emitterCell.yAcceleration = 1000
逐步進(jìn)行以下操作:
- 1) 您可以通過將發(fā)射器單元的內(nèi)容設(shè)置為圖像來設(shè)置發(fā)射器單元。該圖像在
Layer Player
項(xiàng)目中可用拓劝。 - 2) 然后雏逾,使用
VelocityRange
指定初始速度和最大方差。發(fā)射器層使用上述種子創(chuàng)建隨機(jī)數(shù)生成器郑临。隨機(jī)數(shù)生成器通過使用初始值加上和減去范圍值來隨機(jī)化范圍內(nèi)的值栖博。對(duì)于以Range
結(jié)尾的所有屬性,都會(huì)發(fā)生這種隨機(jī)化厢洞。 - 3) 您將顏色設(shè)置為黑色仇让。這樣可以使方差與默認(rèn)的白色不同典奉,從而導(dǎo)致粒子過亮。
- 4) 接下來丧叽,使用與
velocityRange
相同的隨機(jī)化設(shè)置一系列顏色范圍卫玖。這次,隨機(jī)化指定每種顏色的隨機(jī)范圍踊淳。速度值決定了每種顏色在單元的整個(gè)生命周期內(nèi)變化的速度假瞬。 - 5) 在這里,您可以指定如何在整個(gè)圓錐周圍分布
cell
嚣崭。您可以通過設(shè)置發(fā)射器單元的旋轉(zhuǎn)速度和發(fā)射范圍來實(shí)現(xiàn)笨触。emissionRange
定義以弧度指定的圓錐。emissionRange
確定如何在錐體周圍分布發(fā)射器單元雹舀。 - 6) 您將
cell
的壽命設(shè)置為1秒芦劣。該屬性的默認(rèn)值為0
,因此说榆,如果您未顯式設(shè)置它虚吟,則永遠(yuǎn)不會(huì)顯示cell
!每秒的birthRate
也是如此签财。birthRate
的默認(rèn)值為0
串慰,因此必須將其設(shè)置為正數(shù)才能顯示cell
。 - 7) 最后唱蒸,設(shè)置
cell
x
和y
的加速度邦鲫。這些值會(huì)影響粒子發(fā)射的視角。
構(gòu)建并運(yùn)行神汹,然后選擇CAEmitterLayer
庆捺。結(jié)果如下:
返回Xcode
,找到prepare(for:sender :)
并取消注釋該代碼以連接控件表屁魏。
現(xiàn)在滔以,再次構(gòu)建并運(yùn)行該應(yīng)用程序,并使用控件來調(diào)整所有上述屬性以及其他一些屬性:
恭喜你氓拼! 您已經(jīng)完成了精彩的CALayer
之旅你画。 您已經(jīng)看到了9個(gè)有關(guān)如何使用CALayer
及其許多子類的示例。
但是不要在這里停下來桃漾! 打開一個(gè)新項(xiàng)目坏匪,或使用現(xiàn)有項(xiàng)目之一,然后看看如何使用圖層呈队。 您可能可以實(shí)現(xiàn)更好的性能剥槐,或者可以添加一些新的動(dòng)畫來讓您的用戶以及您自己贊嘆不已!
后記
本篇主要講述了
CALayer
的簡單實(shí)用示例宪摧,感興趣的給個(gè)贊或者關(guān)注~~~