版本記錄
| 版本號(hào) | 時(shí)間 |
|---|---|
| V1.0 | 2021.09.04 星期六 |
前言
quartz是一個(gè)通用的術(shù)語,用于描述在iOS和MAC OS X中整個(gè)媒體層用到的多種技術(shù) 包括圖形、動(dòng)畫、音頻、適配。Quart 2D是一組二維繪圖和渲染API,Core Graphic會(huì)使用到這組API,Quartz Core專指Core Animation用到的動(dòng)畫相關(guān)的庫、API和類。CoreGraphics是UIKit下的主要繪圖系統(tǒng),頻繁的用于繪制自定義視圖。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics數(shù)據(jù)結(jié)構(gòu)和函數(shù)可以通過前綴CG來識(shí)別。在app中很多時(shí)候繪圖等操作我們要利用CoreGraphic框架,它能繪制字符串、圖形、漸變色等等,是一個(gè)很強(qiáng)大的工具。感興趣的可以看我另外幾篇。
1. CoreGraphic框架解析(一)—— 基本概覽
2. CoreGraphic框架解析(二)—— 基本使用
3. CoreGraphic框架解析(三)—— 類波浪線的實(shí)現(xiàn)
4. CoreGraphic框架解析(四)—— 基本架構(gòu)補(bǔ)充
5. CoreGraphic框架解析 (五)—— 基于CoreGraphic的一個(gè)簡(jiǎn)單繪制示例 (一)
6. CoreGraphic框架解析 (六)—— 基于CoreGraphic的一個(gè)簡(jiǎn)單繪制示例 (二)
7. CoreGraphic框架解析 (七)—— 基于CoreGraphic的一個(gè)簡(jiǎn)單繪制示例 (三)
8. CoreGraphic框架解析 (八)—— 基于CoreGraphic的一個(gè)簡(jiǎn)單繪制示例 (四)
9. CoreGraphic框架解析 (九)—— 一個(gè)簡(jiǎn)單小游戲 (一)
10. CoreGraphic框架解析 (十)—— 一個(gè)簡(jiǎn)單小游戲 (二)
11. CoreGraphic框架解析 (十一)—— 一個(gè)簡(jiǎn)單小游戲 (三)
12. CoreGraphic框架解析 (十二)—— Shadows 和 Gloss (一)
13. CoreGraphic框架解析 (十三)—— Shadows 和 Gloss (二)
14. CoreGraphic框架解析 (十四)—— Arcs 和 Paths (一)
15. CoreGraphic框架解析 (十五)—— Arcs 和 Paths (二)
16. CoreGraphic框架解析 (十六)—— Lines, Rectangles 和 Gradients (一)
17. CoreGraphic框架解析 (十七)—— Lines, Rectangles 和 Gradients (二)
18. CoreGraphic框架解析 (十八) —— 如何制作Glossy效果的按鈕(一)
19. CoreGraphic框架解析 (十九) —— 如何制作Glossy效果的按鈕(二)
20. CoreGraphic框架解析 (二十) —— Curves and Layers(一)
21. CoreGraphic框架解析 (二十一) —— Curves and Layers(二)
22. CoreGraphic框架解析 (二十二) —— Gradients 和 Contexts的簡(jiǎn)單示例(一)
23. CoreGraphic框架解析 (二十三) —— Gradients 和 Contexts的簡(jiǎn)單示例(二)
24. CoreGraphic框架解析 (二十四) —— 基于Core Graphic的重復(fù)圖案的繪制(一)
25. CoreGraphic框架解析 (二十五) —— 基于Core Graphic的重復(fù)圖案的繪制(二)
26. CoreGraphic框架解析 (二十六) —— 以高效的方式繪制圖案(一)
27. CoreGraphic框架解析 (二十七) —— 以高效的方式繪制圖案(二)
開始
首先看下主要內(nèi)容:
學(xué)習(xí)如何使用
Core Graphics繪制線條、矩形和漸變——從美化table view開始!內(nèi)容來自翻譯。
下面看下寫作環(huán)境:
Swift 5.5, iOS 15, Xcode 13
接著就是主要內(nèi)容了。
Core Graphics 是 iOS 上的一個(gè)很酷的 API。 作為開發(fā)人員,您可以使用它來自定義具有一些簡(jiǎn)潔效果的 UI,通常無需藝術(shù)家參與。 任何與 2-D 繪圖相關(guān)的東西——比如繪制形狀、填充它們并賦予它們漸變 —— 都是使用 Core Graphics 的好選擇。
Core Graphics 的歷史可以追溯到 OS X 的早期,它是當(dāng)今仍在使用的最古老的 API 之一。 也許這就是為什么,對(duì)于許多 iOS 開發(fā)人員來說,Core Graphics 一開始可能有點(diǎn)令人生畏:它是一個(gè)龐大的 API,并且在此過程中會(huì)有很多障礙。 然而,從 Swift 3 開始,C 風(fēng)格的 API 已經(jīng)更新,看起來和感覺就像你熟悉和喜愛的現(xiàn)代 Swift API!
在本教程中,您將構(gòu)建一個(gè) Star Wars Top Trumps 卡片應(yīng)用程序,其中包含一系列星艦:

...以及每艘星艦的詳細(xì)視圖。

在創(chuàng)建此應(yīng)用程序時(shí),您將學(xué)習(xí)如何開始使用 Core Graphics、填充和描邊矩形以及繪制線條和漸變以制作自定義table view cells和背景。
你可能想系好安全帶——是時(shí)候享受 Core Graphics 的樂趣了!
打開入門項(xiàng)目。打開 Sample Projects 文件夾中的起始項(xiàng)目并環(huán)顧四周。具體請(qǐng)看:
-
Starship.swift:在這里,你會(huì)找到這個(gè)應(yīng)用程序的主要模型——
Starship。這是一個(gè)簡(jiǎn)單的結(jié)構(gòu)體,具有Starships的共同屬性。在下面的extension中,您將找到static屬性all,它從位于Resources文件夾中的Starships.json文件中返回所有星際飛船。 - StarshipsViewController.swift:這是應(yīng)用程序的主視圖控制器。它包含所有星艦的數(shù)組并將它們顯示在表格中。
- StarshipDetailViewController.swift:此視圖控制器顯示用戶選擇的星艦所有字段的表格。
構(gòu)建并運(yùn)行應(yīng)用程序。
注意:如果您沒有看到可用于運(yùn)行項(xiàng)目的模擬器,則您可能使用的是舊版本的
Xcode。 您可以從 Apple 的 Developer portal門戶下載Xcode 13。

登陸頁面是 StarshipsViewController,顯示來自星球大戰(zhàn)宇宙的星艦列表。 點(diǎn)擊以選擇Y-wing,應(yīng)用程序?qū)?dǎo)航到該船的詳細(xì)視圖,其中顯示Y-wing的圖像,以及其成本和速度等各種屬性。

這是一個(gè)功能齊全但很無聊的應(yīng)用程序。 是時(shí)候添加一些金光閃閃了!
Analyzing the Table View Style
在本教程中,您將為兩個(gè)表格視圖添加不同的樣式。 更仔細(xì)地觀察這些變化的樣子。
在StarshipsViewController 中,每個(gè)單元格:
- 具有從深藍(lán)色到黑色的漸變。
- 以黃色勾勒,從單元格邊界
inset繪制。

在 StarshipDetailViewController 中:
- 列表本身有一個(gè)從深藍(lán)色到黑色的漸變。
- 每個(gè)單元格都有一個(gè)黃色的分隔線,將它與相鄰的單元格分開。

要繪制這兩種設(shè)計(jì),您只需要知道如何使用 Core Graphics 繪制矩形、漸變和線條,這就是您將要學(xué)習(xí)的內(nèi)容。
Hello, Core Graphics!
雖然本教程涵蓋在 iOS 上使用 Core Graphics,但重要的是要知道 Core Graphics 可用于所有主要的 Apple 平臺(tái),包括: macOS 是 AppKit; iOS 和 tvOS 是 UIKit;并通過 WatchKit 在 Apple Watch 上。
你可以把使用 Core Graphics 想象成在物理畫布上繪畫:繪畫操作的順序很重要。例如,如果您繪制重疊形狀,那么您添加的最后一個(gè)形狀將在頂部并與下面的形狀重疊。
Apple 設(shè)計(jì)了 Core Graphics,因此作為開發(fā)人員,您可以提供有關(guān)繪制內(nèi)容和繪制位置的說明。
Core Graphics Context,由 CGContext 類表示,定義了 where。您告訴上下文要執(zhí)行哪些繪圖操作。有用于繪制位圖圖像、繪制到 PDF 文件以及最常見的直接繪制到 UIView 的 CGContexts。
在這個(gè)繪畫類比中,Core Graphics Context代表畫家的畫布。
Core Graphics Context是State Machines。例如,當(dāng)您設(shè)置填充顏色時(shí),您就是為整個(gè)畫布設(shè)置了它。您繪制的任何形狀都將具有相同的填充顏色,直到您更改它為止。
每個(gè) UIView 都有自己的Core Graphics Context。要使用 Core Graphics 繪制 UIView 的內(nèi)容,您必須在視圖的 draw(_:) 中編寫繪圖代碼。這是因?yàn)?iOS 在調(diào)用 draw(_:) 之前立即設(shè)置了正確的 CGContext 以繪制到視圖中。
現(xiàn)在您了解了如何在 UIKit 中使用 Core Graphics 的基礎(chǔ)知識(shí),是時(shí)候更新您的應(yīng)用程序了!
Drawing Rectangles
首先,通過從File菜單中選擇New ? File…來創(chuàng)建一個(gè)視圖文件。 選擇 Cocoa Touch Class,單擊 Next,然后將類名設(shè)置為 StarshipListCellBackground。 使其成為 UIView 的子類,然后創(chuàng)建類文件。 將以下代碼添加到您的新類中:
override func draw(_ rect: CGRect) {
// 1
guard let context = UIGraphicsGetCurrentContext() else {
return
}
// 2
context.setFillColor(UIColor.yellow.cgColor)
// 3
context.fill(bounds)
}
逐行分解:
- 1) 首先,您使用
UIGraphicsGetCurrentContext()獲取此UIView實(shí)例的當(dāng)前CGContext。請(qǐng)記住,iOS 會(huì)在調(diào)用draw(_:)之前自動(dòng)為您設(shè)置。如果由于任何原因無法獲取上下文,則應(yīng)盡早從該方法返回。 - 2) 然后,您在上下文本身上設(shè)置填充顏色。
- 3) 最后,您告訴它填充視圖的邊界。
如您所見,Core Graphics API 不包含直接繪制填充顏色的形狀的方法。相反,有點(diǎn)像向特定畫筆添加油漆,您將顏色設(shè)置為 CGContext 的狀態(tài),然后告訴上下文分別用該顏色繪制什么。
您可能還注意到,當(dāng)您在上下文中調(diào)用 setFillColor(_:) 時(shí),您沒有提供標(biāo)準(zhǔn)的 UIColor。相反,您必須使用 CGColor,這是 Core Graphics 在內(nèi)部用來表示顏色的基本數(shù)據(jù)類型。只需訪問任何 UIColor 的 CGColor 屬性,即可將 UIColor 轉(zhuǎn)換為 CGColor 非常容易。
1. Showing Your New Cell
要查看您的新視圖的情況,請(qǐng)打開 StarshipListCell.swift。這是一個(gè) UITableViewCell 子類,用于在 StarshipsViewController 中顯示星艦。在awakeFromNib中,在方法末尾添加以下代碼:
backgroundView = StarshipListCellBackground()
此代碼將單元格的背景視圖設(shè)置為新視圖的背景視圖。 構(gòu)建并運(yùn)行應(yīng)用程序,你會(huì)在每個(gè)單元格中看到一個(gè)可愛的黃色背景。

驚人的! 您現(xiàn)在可以使用 Core Graphics 進(jìn)行繪圖。 不管你信不信,你已經(jīng)學(xué)會(huì)了很多重要的技巧:如何獲取要繪制的上下文、如何更改填充顏色以及如何用顏色填充矩形。 你可以用它制作一些可愛的用戶界面。
但是您將更進(jìn)一步,了解制作出色 UI 的最有價(jià)值的技術(shù)之一:漸變!
Creating New Colors
你將在這個(gè)項(xiàng)目中一次又一次地使用相同的顏色,所以為 UIColor 創(chuàng)建一個(gè)擴(kuò)展,使它們易于訪問。 轉(zhuǎn)到 File ? New ? File... 并創(chuàng)建一個(gè)名為 UIColor+Extensions 的新 Swift 文件。 將文件內(nèi)容替換為以下內(nèi)容:
import UIKit
extension UIColor {
public static let starwarsYellow =
UIColor(red: 250 / 255, green: 202 / 255, blue: 56 / 255, alpha: 1.0)
public static let starwarsSpaceBlue =
UIColor(red: 5 / 255, green: 10 / 255, blue: 85 / 255, alpha: 1.0)
public static let starwarsStarshipGrey =
UIColor(red: 159 / 255, green: 150 / 255, blue: 135 / 255, alpha: 1.0)
}
此代碼定義了三種新顏色,您可以將它們作為 UIColor 上的靜態(tài)屬性進(jìn)行訪問。
Drawing Gradients
接下來,因?yàn)槟阋谶@個(gè)項(xiàng)目中繪制許多漸變,添加一個(gè)繪制它們的輔助方法。 這將通過將梯度代碼保存在一個(gè)地方并避免重復(fù)自己來簡(jiǎn)化任務(wù)。
選擇 File ? New ? File... 并創(chuàng)建一個(gè)名為 CGContext+Extensions 的新 Swift 文件。 將文件內(nèi)容替換為以下內(nèi)容:
import CoreGraphics
extension CGContext {
func drawLinearGradient(
in rect: CGRect,
startingWith startColor: CGColor,
finishingWith endColor: CGColor
) {
// 1
let colorSpace = CGColorSpaceCreateDeviceRGB()
// 2
let locations: [CGFloat] = [0.0, 1.0]
// 3
let colors = [startColor, endColor] as CFArray
// 4
guard let gradient = CGGradient(
colorsSpace: colorSpace,
colors: colors,
locations: locations
) else {
return
}
}
}
這種方法有很多:
- 1) 首先,設(shè)置正確的色彩空間
(color space)。您可以使用顏色空間做很多事情,但您幾乎總是希望使用CGColorSpaceCreateDeviceRGB來使用標(biāo)準(zhǔn)的設(shè)備相關(guān) RGB 顏色空間。 - 2) 接下來,設(shè)置一個(gè)數(shù)組來跟蹤漸變范圍內(nèi)每種顏色的位置。值
0表示漸變開始,1表示漸變結(jié)束。
注意:如果需要,您可以在漸變中使用三種或更多顏色,并且您可以在像這樣的數(shù)組中設(shè)置每種顏色在漸變中的開始位置。這對(duì)某些效果很有用。
- 3) 之后,您使用傳遞給方法的顏色創(chuàng)建一個(gè)數(shù)組。請(qǐng)注意這里使用的是
CFArray,而不是Array,因?yàn)槟褂玫氖禽^低級(jí)別的C API。 - 4) 然后,通過初始化
CGGradient對(duì)象來創(chuàng)建漸變,傳入顏色空間、顏色數(shù)組和之前創(chuàng)建的位置。如果無論出于何種原因,可選初始化程序失敗,您都會(huì)提前返回。
你現(xiàn)在有一個(gè)漸變參考,但它實(shí)際上還沒有繪制任何東西——它只是一個(gè)指向你稍后實(shí)際繪制時(shí)將使用的信息的指針。差不多是繪制漸變的時(shí)候了,但在此之前,是時(shí)候了解更多理論了。
1. The Graphics State Stack
請(qǐng)記?。?code>Core Graphics Contexts是狀態(tài)機(jī)。 在上下文上設(shè)置狀態(tài)時(shí)必須小心,尤其是在傳遞上下文的函數(shù)中,或者在這種情況下,上下文本身的方法,因?yàn)樵谛薷纳舷挛闹澳鸁o法知道上下文的狀態(tài)。 考慮 UIView 中的以下代碼:
override func draw(_ rect: CGRect) {
// ... get context
context.setFillColor(UIColor.red.cgColor)
drawBlueCircle(in: context)
context.fill(someRect)
}
// ... many lines later
func drawBlueCircle(in context: CGContext) {
context.setFillColor(UIColor.blue.cgColor)
context.addEllipse(in: bounds)
context.drawPath(using: .fill)
}
看一眼這段代碼,你可能認(rèn)為它會(huì)在視圖中繪制一個(gè)紅色矩形和一個(gè)藍(lán)色圓圈,但你錯(cuò)了! 相反,這段代碼繪制了一個(gè)藍(lán)色矩形和一個(gè)藍(lán)色圓圈——但為什么呢?

因?yàn)?drawBlueCircle(in:) 在上下文中設(shè)置了藍(lán)色填充顏色,并且因?yàn)樯舷挛氖且粋€(gè)狀態(tài)機(jī),所以這會(huì)覆蓋之前設(shè)置的紅色填充顏色。
這就是 saveGState() 及其伙伴方法 restoreGState())的用武之地!
每個(gè) CGContext 都維護(hù)一個(gè)圖形狀態(tài)堆棧,其中包含當(dāng)前繪圖環(huán)境的大部分(盡管不是全部)方面。 saveGState() 將當(dāng)前狀態(tài)的副本推送到圖形狀態(tài)堆棧上,然后您可以使用 restoreGState() 將上下文恢復(fù)到該狀態(tài),并在此過程中從堆棧中刪除該狀態(tài)。
在上面的例子中,你應(yīng)該像這樣修改 drawBlueLines(in:):
func drawBlueCircle(in context: CGContext) {
context.saveGState()
context.setFillColor(UIColor.blue.cgColor)
context.addEllipse(in: bounds)
context.drawPath(using: .fill)
context.restoreGState()
}

您可以通過在本教程頂部或底部的下載材料按鈕中打開RedBluePlayground.playground 來測(cè)試這一點(diǎn)。
2. Completing the Gradient
掌握了圖形狀態(tài)堆棧的知識(shí),是時(shí)候完成背景漸變的繪制了。 將以下內(nèi)容添加到 drawLinearGradient(in:startingWith:finishingWith:)的末尾:
// 5
let startPoint = CGPoint(x: rect.midX, y: rect.minY)
let endPoint = CGPoint(x: rect.midX, y: rect.maxY)
// 6
saveGState()
// 7
addRect(rect)
clip()
drawLinearGradient(
gradient,
start: startPoint,
end: endPoint,
options: CGGradientDrawingOptions())
restoreGState()
這是該代碼的細(xì)分:
- 5) 首先計(jì)算漸變的起點(diǎn)和終點(diǎn)。您將其設(shè)置為從矩形頂部中間到底部中間的一條線。有用的是,
CGRect包含一些實(shí)例屬性,例如midX和maxY,使這變得非常簡(jiǎn)單。 - 6) 接下來,因?yàn)槟鷮⒁薷纳舷挛牡臓顟B(tài),所以您保存其圖形狀態(tài)并通過恢復(fù)它來結(jié)束該方法。
- 7) 最后,在提供的矩形中繪制漸變。
drawLinearGradient(_:start:end:options:)是實(shí)際繪制漸變的方法,但除非另有說明,否則它將用漸變填充整個(gè)上下文,即您的情況下的整個(gè)視圖。在這里,您只想填充提供的矩形中的漸變。為此,您需要了解clipping。
clipping是 Core Graphics 中的一個(gè)很棒的功能,它可以讓您將繪圖限制為任意形狀。您所要做的就是將形狀添加到上下文中,但不是像通常那樣填充它,而是在上下文上調(diào)用 clip(),然后將所有未來的繪圖限制在該區(qū)域。
因此,在這種情況下,在最終調(diào)用 drawLinearGradient(_:start:end:options:) 繪制漸變之前,在上下文和剪輯上設(shè)置提供的矩形。
是時(shí)候試試這個(gè)方法了!打開 StarshipListCellBackground.swift 并在guard語句中獲取當(dāng)前 UIGraphicsContext 后,將代碼替換為以下內(nèi)容:
context.drawLinearGradient(
in: bounds,
startingWith: UIColor.starwarsSpaceBlue.cgColor,
finishingWith: UIColor.black.cgColor)
構(gòu)建并運(yùn)行

您現(xiàn)在已經(jīng)為自定義單元格添加了漸變背景。 干得好,然而,公平地說,成品現(xiàn)在看起來并不好看。 是時(shí)候用一些標(biāo)準(zhǔn)的 UIKit 主題來解決這個(gè)問題了。
Fixing the Theme
打開 StarshipsViewController.swift。 在 viewDidLoad() 的末尾,添加以下內(nèi)容:
tableView.separatorStyle = .none
tableView.backgroundColor = .starwarsSpaceBlue
然后,在 tableView(_:cellForRowAt:) 中,就在返回單元格之前,設(shè)置文本的顏色:
cell.textLabel?.textColor = .starwarsStarshipGrey
這將移除單元格分隔符并為表格提供一些漂亮的星艦顏色。
接下來,打開 AppDelegate.swift 并在 application(_:didFinishLaunchingWithOptions:) 中,在返回之前添加以下內(nèi)容:
// Theming
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithOpaqueBackground()
barAppearance.backgroundColor = .starwarsSpaceBlue
barAppearance.titleTextAttributes = [
.foregroundColor: UIColor.starwarsStarshipGrey
]
UINavigationBar.appearance().tintColor = .starwarsYellow
UINavigationBar.appearance().barStyle = .black
UINavigationBar.appearance().standardAppearance = barAppearance
UINavigationBar.appearance().scrollEdgeAppearance = barAppearance
這將使用 iOS 13 中引入的 UINavigationBarAppearance 類設(shè)置導(dǎo)航欄的外觀以匹配表格的外觀。
構(gòu)建并運(yùn)行應(yīng)用程序。

這樣更好!您的星際飛船的table view開始看起來像太空時(shí)代。
Stroking Paths
Core Graphics 中的Stroking意味著沿著路徑繪制一條線,而不是像以前那樣填充它。
當(dāng) Core Graphics 描邊路徑時(shí),它會(huì)在路徑的確切邊緣的中間繪制描邊線。這可能會(huì)導(dǎo)致一些常見問題。
1. Outside the Bounds
首先,如果你在一個(gè)矩形的邊緣繪制——例如一個(gè)邊框——Core Graphics 默認(rèn)不會(huì)繪制一半的描邊路徑。
為什么?因?yàn)闉?UIView 設(shè)置的上下文僅擴(kuò)展到視圖的邊界。想象一下在視圖邊緣使用單點(diǎn)邊框進(jìn)行描邊。因?yàn)?Core Graphics 沿著路徑的中間向下劃,線將在視圖邊界外半點(diǎn)和視圖邊界內(nèi)半點(diǎn)。
一個(gè)常見的解決方案是在每個(gè)方向上將描邊矩形的路徑inset為線條寬度的一半,因此它位于視圖內(nèi)。
下圖顯示了一個(gè)黃色矩形,在灰色背景上有一個(gè)點(diǎn)寬的紅色描邊,以一點(diǎn)間隔條紋。在左圖中,描邊路徑遵循視圖的邊界并已被裁剪。您可以看到這一點(diǎn),因?yàn)榧t線是灰色方塊寬度的一半。在右圖中,描邊路徑inset半個(gè)點(diǎn),現(xiàn)在具有正確的線寬。

2. Anti-Aliasing
其次,您需要了解可能影響邊框外觀的抗鋸齒效果??逛忼X是渲染引擎用來在顯示的圖形不能完美映射到設(shè)備上的物理像素時(shí)避免出現(xiàn)“鋸齒狀”邊緣和線條的技術(shù)。
以上一段中視圖周圍的單點(diǎn)邊框?yàn)槔H绻吙蜃裱晥D的邊界,那么 Core Graphics 將嘗試在矩形的任一側(cè)繪制一條半點(diǎn)寬的線。
在非 Retina 顯示器上,一個(gè)點(diǎn)等于設(shè)備上的一個(gè)像素。不可能只點(diǎn)亮一個(gè)像素的一半,因此 Core Graphics 將使用抗鋸齒來繪制兩個(gè)像素,但在較淺的陰影中僅顯示單個(gè)像素的外觀。
在以下幾組截圖中,左圖為非 Retina 顯示屏,中間圖為scale為 2 的 Retina 顯示屏,第三幅圖為scale為 3 的 Retina 顯示屏。
對(duì)于第一個(gè)圖表,請(qǐng)注意 2x 圖像如何不顯示任何抗鋸齒,因?yàn)辄S色矩形兩側(cè)的半點(diǎn)落在像素邊界上。但是,在 1x 和 3x 圖像中,會(huì)出現(xiàn)抗鋸齒。

在下一組截圖中,描邊矩形已inset半點(diǎn)。 因此,筆劃線與點(diǎn)精確對(duì)齊,從而與像素邊界對(duì)齊。 請(qǐng)注意沒有鋸齒偽影。

Adding a Border
回到您的應(yīng)用程序! cell開始看起來不錯(cuò),但您將添加另一種以使它們脫穎而出。 這一次,您將在單元格邊緣繪制一個(gè)亮黃色框。
您已經(jīng)知道如何輕松填充矩形。 好吧,在它們周圍描邊也很容易。
打開 StarshipListCellBackground.swift 并將以下內(nèi)容添加到 draw(_:) 的底部:
let strokeRect = bounds.insetBy(dx: 4.5, dy: 4.5)
context.setStrokeColor(UIColor.starwarsYellow.cgColor)
context.setLineWidth(1)
context.stroke(strokeRect)
在這里,您創(chuàng)建一個(gè)用于描邊的矩形,該矩形在 x 和 y 方向上從背景矩形inset 4.5 個(gè)點(diǎn)。 然后,將描邊顏色設(shè)置為黃色,將線寬設(shè)置為 1 磅,最后對(duì)矩形進(jìn)行描邊。 構(gòu)建并運(yùn)行您的項(xiàng)目。

現(xiàn)在,您的星艦列表看起來像是來自遙遠(yuǎn)的星系!
Building a Card Layout
雖然 StarshipsViewController 看起來很花哨,但 StarshipDetailViewController 仍然需要一些修飾!

對(duì)于此視圖,您將首先使用自定義 UITableView 子類在 table view 背景上繪制漸變。
創(chuàng)建一個(gè)新的 Cocoa Touch Class 文件,使其成為 UITableView 的子類并命名為 StarshipTableView。 將以下內(nèi)容添加到新類:
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
context.drawLinearGradient(
in: bounds,
startingWith: UIColor.starwarsSpaceBlue.cgColor,
finishingWith: UIColor.black.cgColor)
}
這應(yīng)該看起來很熟悉。 在新的table view子類的 draw(_:)方法中,您獲取當(dāng)前的 CGContext,然后在視圖的邊界中繪制漸變,從頂部的藍(lán)色開始到底部的黑色。 簡(jiǎn)單的!
打開 Main.storyboard 并單擊 Starship Detail View Controller 場(chǎng)景中的 TableView。 在Identity inspector中,將類設(shè)置為新的 StarshipTableView。

構(gòu)建并運(yùn)行應(yīng)用程序,然后點(diǎn)擊Y-wing。

你的detail view現(xiàn)在有一個(gè)從上到下的漂亮的全屏漸變,但table view中的單元格掩蓋了效果的最佳部分。 是時(shí)候解決這個(gè)問題并為細(xì)節(jié)單元格添加更多風(fēng)格了。
打開 StarshipDetailViewController.swift 并在 tableView(_:cellForRowAt:) 的底部,在返回item field的單元格之前,添加以下內(nèi)容:
cell.textLabel?.textColor = .starwarsStarshipGrey
cell.detailTextLabel?.textColor = .starwarsYellow
cell.backgroundColor = .clear
這只是將單元格的字段名稱和值設(shè)置為更適合您的星球大戰(zhàn)主題的顏色,并將背景顏色設(shè)置為clear。
然后,在tableView(_:cellForRowAt:)之后,添加以下方法來設(shè)置table view header的樣式:
override func tableView(
_ tableView: UITableView,
willDisplayHeaderView view: UIView,
forSection section: Int
) {
view.tintColor = .starwarsYellow
if let header = view as? UITableViewHeaderFooterView {
header.textLabel?.textColor = .starwarsSpaceBlue
}
}
在這里,您將表視圖標(biāo)題視圖的色調(diào)顏色設(shè)置為主題黃色,給它一個(gè)黃色背景,并將其文本顏色設(shè)置為主題藍(lán)色。
Drawing Lines
作為最后一點(diǎn),您將在詳細(xì)信息視圖中為每個(gè)單元格添加一個(gè)splitter。 打開 StarshipFieldCell.swift并將以下內(nèi)容添加到類中:
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let y = bounds.maxY - 0.5
let minX = bounds.minX
let maxX = bounds.maxX
context.setStrokeColor(UIColor.starwarsYellow.cgColor)
context.setLineWidth(1.0)
context.move(to: CGPoint(x: minX, y: y))
context.addLine(to: CGPoint(x: maxX, y: y))
context.strokePath()
}
在這里,您使用 Core Graphics 在單元格邊界的底部繪制一條線。 請(qǐng)注意所使用的 y 值如何比視圖邊界小半點(diǎn),以確保splitter完全繪制在單元格內(nèi)。
現(xiàn)在,您需要實(shí)際繪制顯示splitter的線。
要在 A 和 B 之間畫一條線,首先要移動(dòng)到 A 點(diǎn),這不會(huì)導(dǎo)致 Core Graphics 繪制任何內(nèi)容。 然后向 B 點(diǎn)添加一條線,這會(huì)將從 A 點(diǎn)到 B 點(diǎn)的線添加到上下文中。 然后您可以調(diào)用 strokePath() 來描邊線。
構(gòu)建并運(yùn)行您的應(yīng)用程序。 然后,打開 Y 翼詳細(xì)視圖。 美麗的!

如果本教程有點(diǎn)難以理解,或者您想確保涵蓋您的基礎(chǔ)知識(shí),請(qǐng)查看 Beginning Core Graphics 視頻系列。
如果您正在尋找更高級(jí)的東西,請(qǐng)查看中Intermediate Core Graphics課程。
如果您覺得還不能完成整個(gè)課程,請(qǐng)嘗試 Core Graphics Article Series系列,在那里您將學(xué)習(xí)如何使用 Core Graphics 從頭開始繪制整個(gè)應(yīng)用程序,包括圖形!
后記
本篇主要講述了關(guān)于線、矩形和漸變的繪制,感興趣的給個(gè)贊或者關(guān)注~~~
