CoreGraphic框架解析 (十六)—— Lines, Rectangles 和 Gradients (一)

版本記錄

版本號 時間
V1.0 2019.02.12 星期二

前言

quartz是一個通用的術(shù)語,用于描述在iOSMAC OS X 中整個媒體層用到的多種技術(shù) 包括圖形顶伞、動畫廉油、音頻、適配撩笆。Quart 2D 是一組二維繪圖和渲染API捺球,Core Graphic會使用到這組APIQuartz Core專指Core Animation用到的動畫相關(guān)的庫夕冲、API和類氮兵。CoreGraphicsUIKit下的主要繪圖系統(tǒng),頻繁的用于繪制自定義視圖歹鱼。Core Graphics是高度集成于UIView和其他UIKit部分的泣栈。Core Graphics數(shù)據(jù)結(jié)構(gòu)和函數(shù)可以通過前綴CG來識別。在app中很多時候繪圖等操作我們要利用CoreGraphic框架,它能繪制字符串南片、圖形掺涛、漸變色等等,是一個很強大的工具疼进。感興趣的可以看我另外幾篇薪缆。
1. CoreGraphic框架解析(一)—— 基本概覽
2. CoreGraphic框架解析(二)—— 基本使用
3. CoreGraphic框架解析(三)—— 類波浪線的實現(xiàn)
4. CoreGraphic框架解析(四)—— 基本架構(gòu)補充
5. CoreGraphic框架解析 (五)—— 基于CoreGraphic的一個簡單繪制示例 (一)
6. CoreGraphic框架解析 (六)—— 基于CoreGraphic的一個簡單繪制示例 (二)
7. CoreGraphic框架解析 (七)—— 基于CoreGraphic的一個簡單繪制示例 (三)
8. CoreGraphic框架解析 (八)—— 基于CoreGraphic的一個簡單繪制示例 (四)
9. CoreGraphic框架解析 (九)—— 一個簡單小游戲 (一)
10. CoreGraphic框架解析 (十)—— 一個簡單小游戲 (二)
11. CoreGraphic框架解析 (十一)—— 一個簡單小游戲 (三)
12. CoreGraphic框架解析 (十二)—— Shadows 和 Gloss (一)
13. CoreGraphic框架解析 (十三)—— Shadows 和 Gloss (二)
14. CoreGraphic框架解析 (十四)—— Arcs 和 Paths (一)
15. CoreGraphic框架解析 (十五)—— Arcs 和 Paths (二)

開始

首先看下寫作環(huán)境

Swift 4.2, iOS 12, Xcode 10

在本教程中,您將學(xué)習(xí)如何使用Core Graphics繪制線條伞广,矩形和漸變 - 從美化表格視圖開始拣帽!

這篇將揭開Core Graphics的神秘面紗。您將通過實際練習(xí)逐步學(xué)習(xí)API嚼锄,首先使用Core Graphics美化table views减拭。

Core Graphics是iOS上非常酷的API灾票。作為開發(fā)人員峡谊,您可以使用它來自定義您的UI,并使用一些非常簡潔的效果刊苍,通常甚至無需讓設(shè)計師參與其中既们。任何與2D繪圖相關(guān)的東西 - 比如繪制形狀,填充它們并賦予它們漸變 - 都是使用Core Graphics的一個很好的選擇正什。

Core Graphics的歷史可以追溯到OS X的早期階段啥纸,是目前仍在使用的最古老的API之一。也許這就是為什么婴氮,對于許多iOS開發(fā)人員來說斯棒,Core Graphics起初可能有些令人生畏:它是一個龐大的API,并且有很多障礙可以發(fā)現(xiàn)主经。但是荣暮,自從Swift 3以來,C風(fēng)格的API已經(jīng)更新罩驻,看起來和感覺就像您熟悉和喜愛的現(xiàn)代Swift API穗酥!

在本教程中,您將構(gòu)建一個Star Wars Top Trumps應(yīng)用程序惠遏,該應(yīng)用程序由包含Starships列表的主視圖組成:

以及一個每個Starship的詳細視圖

在創(chuàng)建此應(yīng)用程序時砾跃,您將學(xué)習(xí)如何開始使用Core Graphics,如何填充和描邊矩形以及如何繪制線條和漸變以制作自定義表格視圖單元格和背景节吮。

是時候與Core Graphics享受一些樂趣了抽高!

打開入門項目并快速瀏覽一下。該應(yīng)用程序基于Xcode提供的Master-Detail App模板透绩。主視圖控制器包含Star Ships列表翘骂,詳細視圖控制器顯示每艘船的詳細信息壁熄。

打開MasterViewController.swift。在該類的頂部雏胃,注意一個starships變量,它包含Starship類型的數(shù)組和StarshipDataProvider類型的dataProvider變量瞭亮。

通過Command-單擊StarshipDataProvider并選擇Jump to Definition跳轉(zhuǎn)到StarshipDataProvider.swift。這是一個簡單的類,它讀取bundle文件Starships.json,并將內(nèi)容轉(zhuǎn)換為Starship數(shù)組。

你可以在Starship.swift找到Starship的定義衷畦。它只是一個簡單的結(jié)構(gòu)體栗涂,具有Starships常見屬性的屬性。

接下來祈争,打開DetailViewController.swift斤程。在類定義為枚舉之前定義在文件的頂部,FieldsToDisplay菩混,它定義要在枚舉中顯示的Starship屬性的人類可讀標題忿墅。在這個文件中,tableView(_:cellForRowAt :)只是一個很大的switch語句沮峡,用于將每個Starship屬性的數(shù)據(jù)格式化為正確的格式疚脐。

構(gòu)建并運行應(yīng)用程序。

登陸頁面是MasterViewController邢疙,顯示星球大戰(zhàn)宇宙中的星艦列表棍弄。 點擊以選擇X-wing,應(yīng)用程序?qū)?dǎo)航到該船的詳細視圖秘症,其中顯示了X翼的圖像,然后是各種屬性式矫,例如它的成本和飛行速度乡摹。

這是一個功能齊全,如果非常無聊的應(yīng)用程序采转。 是時候添加一些bling了聪廉!


Analyzing the Table View Style

在本教程中瞬痘,您將為兩個不同的表視圖添加不同的樣式。 仔細看看這些變化是什么樣的板熊。

在主視圖控制器中框全,每個單元格:

  • 有從深藍色到黑色的漸變色。
  • 以黃色勾勒出輪廓干签,從cell bounds 有一定的inset津辩。

并在詳細視圖控制器中:

  • table本身有從深藍色到黑色的漸變色。
  • 每個cell都有一個黃色分離線容劳,將其與相鄰cell分開喘沿。

要繪制這兩種設(shè)計,您只需要知道如何使用Core Graphics繪制矩形竭贩,漸變和線條蚜印,這正是您將要學(xué)習(xí)的內(nèi)容。


Hello, Core Graphics!

雖然本教程涵蓋了在iOS上使用Core Graphics留量,但重要的是要知道Core Graphics可用于所有主要的Apple平臺窄赋,包括通過AppKitMacOS,iOS和通過UIKittvOS以及通過WatchKitApple Watch楼熄。

您可以考慮使用Core Graphics忆绰,如在物理畫布上繪畫;繪圖操作的順序很重要孝赫。例如较木,如果您繪制重疊的形狀,那么您添加的最后一個將位于頂部并與下面的重疊青柄。

Apple以這樣的方式構(gòu)建Core Graphics伐债,使您作為開發(fā)人員在單獨的時刻提供有關(guān)繪制內(nèi)容的說明而不是在何處繪制。

CGContext類表示的核心圖形上下文定義了where致开。您可以告訴上下文要執(zhí)行的繪制操作峰锁。 CGContexts用于繪制到位圖圖像,繪制為PDF文件双戳,最常見的是直接繪制到UIView中虹蒋。

在這個繪畫類比中,核心圖形上下文代表畫家繪制的畫布飒货。

核心圖形上下文是狀態(tài)機(State Machines)魄衅。也就是說,當您設(shè)置填充顏色時塘辅,可以為整個畫布設(shè)置填充顏色晃虫,并且在您更改之前,您繪制的任何形狀都將具有相同的填充顏色扣墩。

每個UIView都有自己的核心圖形上下文哲银。要使用Core Graphics繪制UIView的內(nèi)容扛吞,必須在視圖的draw(_ :)中編寫繪圖代碼。這是因為iOS在調(diào)用draw(_ :)之前設(shè)置了正確的CGContext以便繪制到視圖中荆责。

現(xiàn)在您了解了如何在UIKit中使用Core Graphics的基礎(chǔ)知識滥比,現(xiàn)在是時候更新您的應(yīng)用了!


Drawing Rectangles

首先做院,通過從“文件”菜單中選擇New ? File…來創(chuàng)建新的視圖文件盲泛。選擇Cocoa Touch Class,按Next山憨,然后將類名設(shè)置為StarshipsListCellBackground查乒。使其成為UIView的子類,然后創(chuàng)建類文件郁竟。將以下代碼添加到新類:

override func draw(_ rect: CGRect) {
  // 1
  guard let context = UIGraphicsGetCurrentContext() else {
    return
  }
  // 2  
  context.setFillColor(UIColor.red.cgColor)
  // 3
  context.fill(bounds)
}

下面逐行分析:

  • 1) 首先玛迄,使用UIGraphicsGetCurrentContext()獲取此UIView實例的當前CGContext。請記住棚亩,iOS會在調(diào)用draw(_ :)之前自動為您設(shè)置蓖议。如果由于任何原因無法獲取上下文,則可以從方法中提前返回讥蟆。
  • 2) 然后勒虾,在上下文本身上設(shè)置填充顏色。
  • 3) 最后瘸彤,您告訴它填充視圖的邊界修然。

如您所見,Core Graphics API不包含直接繪制填充顏色的形狀的方法质况。相反愕宋,有點像添加油漆到特定的畫筆,你將顏色設(shè)置為CGContext的狀態(tài)结榄,然后中贝,你告訴上下文分別用該顏色繪制什么。

您可能還注意到臼朗,當您在上下文中調(diào)用setFillColor(_ :)時邻寿,您沒有提供標準的UIColor。相反视哑,您必須使用CGColor绣否,這是Core Graphics內(nèi)部用于表示顏色的基本數(shù)據(jù)類型。只需訪問任何UIColor的cgColor屬性挡毅,將UIColor轉(zhuǎn)換為CGColor非常容易蒜撮。

1. Showing Your New Cell

要查看您的新視圖,請打開MasterViewController.swift慷嗜。在tableView(_:cellForRowAt :)中淀弹,在方法的第一行中出現(xiàn)單元格后立即添加以下代碼:

if !(cell.backgroundView is StarshipsListCellBackground) {
  cell.backgroundView = StarshipsListCellBackground()
}
    
if !(cell.selectedBackgroundView is StarshipsListCellBackground) {
  cell.selectedBackgroundView = StarshipsListCellBackground()
}

此代碼將單元格的背景視圖設(shè)置為新視圖的背景視圖。 構(gòu)建并運行應(yīng)用程序庆械,您將在每個單元格中看到可愛的薇溃,如果花哨的紅色背景。

驚人缭乘! 您現(xiàn)在可以使用Core Graphics進行繪制沐序。 不管你信不信,你已經(jīng)學(xué)會了一系列非常重要的技巧:如何繪制上下文堕绩,如何更改填充顏色以及如何用顏色填充矩形策幼。 你可以用它制作一些非常漂亮的用戶界面。

但是你要更進一步奴紧,學(xué)習(xí)一種最有用的技術(shù)來制作優(yōu)秀的用戶界面:漸變特姐!


Creating New Colors

您將在此項目中反復(fù)使用相同的顏色,因此為UIColor創(chuàng)建一個擴展黍氮,以使這些顏色易于訪問唐含。 轉(zhuǎn)到File ? New ? File…并創(chuàng)建一個名為UIColorExtensions.swift的新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)屬性的形式訪問這些顏色捷枯。


Drawing Gradients

接下來,由于您要在此項目中繪制大量漸變专执,因此請?zhí)砑虞o助方法來繪制漸變淮捆。 這將通過將漸變代碼保存在一個位置來簡化項目,并避免重復(fù)自己本股。

選擇File ? New ? File…并創(chuàng)建一個名為CGContextExtensions.swift的新Swift文件攀痊。 用以下內(nèi)容替換文件的內(nèi)容:

import UIKit

extension CGContext {
  func drawLinearGradient(
    in rect: CGRect, 
    startingWith startColor: CGColor, 
    finishingWith endColor: CGColor
  ) {
    // 1
    let colorSpace = CGColorSpaceCreateDeviceRGB()

    // 2
    let locations = [0.0, 1.0] as [CGFloat]    

    // 3
    let colors = [startColor, endColor] as CFArray

    // 4
    guard let gradient = CGGradient(
      colorsSpace: colorSpace, 
      colors: colors, 
      locations: locations
    ) else {
      return
    }
  }
}

這個方法做了很多:

  • 1) 首先,設(shè)置正確的色彩空間痊末。您可以使用色彩空間做很多事情蚕苇,但是您幾乎總是希望使用CGColorSpaceCreateDeviceRGB來使用與設(shè)備相關(guān)的標準RGB色彩空間。
  • 2) 接下來凿叠,設(shè)置一個數(shù)組涩笤,跟蹤漸變范圍內(nèi)每種顏色的位置。值0表示漸變的開始盒件,1表示漸變的結(jié)束蹬碧。

注意:如果需要,可以在漸變中使用三種或更多顏色炒刁,并且可以設(shè)置每種顏色在漸變中的位置恩沽,就像這樣的數(shù)組。這對某些效果很有用翔始。

  • 3) 之后罗心,使用傳遞給方法的顏色創(chuàng)建一個數(shù)組里伯。注意在這里使用CFArray而不是Array,因為您正在使用較低級別的C API渤闷。
  • 4) 然后疾瓮,通過初始化CGGradient對象,傳入顏色空間飒箭,顏色數(shù)組和先前創(chuàng)建的位置來創(chuàng)建漸變狼电。如果由于某種原因,可選的初始化程序失敗弦蹂,則提前返回肩碟。

你現(xiàn)在有一個漸變引用,但它實際上還沒有繪制任何東西 - 它只是一個指向你稍后實際繪制時使用的信息的指針⊥勾唬現(xiàn)在幾乎是繪制漸變的時候了削祈,但在你做之前,還需要更多的理論脑漫。

1. The Graphics State Stack

請記住岩瘦,Core Graphics上下文是狀態(tài)機。 在上下文中設(shè)置狀態(tài)時必須要小心窿撬,特別是在傳遞上下文的函數(shù)中启昧,或者在本例中是上下文本身的方法,因為在修改上下文之前無法知道上下文的狀態(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)
}

看一下這段代碼密末,您可能會認為它會在視圖中繪制一個紅色矩形和一個藍色圓圈,但你錯了跛璧! 相反严里,這段代碼繪制了一個藍色矩形和一個藍色圓圈 - 但為什么呢?

因為drawBlueCircle(in :)在上下文中設(shè)置了藍色填充顏色追城,并且因為上下文是狀態(tài)機刹碾,所以它會覆蓋先前的紅色填充顏色集。

這就是saveGState()及其伙伴方法restoreGState()的用武之地座柱!

每個CGContext都維護一個圖形狀態(tài)的堆棧迷帜,其中包含當前繪圖環(huán)境的大部分(盡管不是全部)方面。 saveGState()將當前狀態(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來自行測試锦针。

2. Completing the Gradient

掌握有關(guān)圖形狀態(tài)堆棧的知識,是時候完成繪制背景漸變了。 將以下內(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()
  • 5) 首先計算漸變的起點和終點奈搜。您可以將其設(shè)置為從矩形的頂部中間到底部中間的線悉盆。有用的是,CGRect包含一些實例變量馋吗,如midXmaxY舀瓢,這使得這非常簡單。
  • 6) 接下來耗美,由于您即將修改上下文的狀態(tài),因此您可以保存其圖形狀態(tài)并通過還原它來結(jié)束該方法航缀。
  • 7) 最后商架,在提供的矩形中繪制漸變。 drawLinearGradient(_:start:end:options :)是實際繪制漸變的方法芥玉,但除非另有說明蛇摸,否則它將使用漸變填充整個上下文,即整個視圖灿巧。在這里赶袄,您只想填充提供的矩形中的漸變。要做到這一點抠藕,你需要了解clipping饿肺。

剪切(clipping)Core Graphics中一個非常棒的功能,可以將繪圖限制為任意形狀盾似。您所要做的就是將形狀添加到上下文中敬辣,然后,不要像通常那樣填充它零院,而是在上下文中調(diào)用clip()溉跃,然后將所有未來的繪制限制到該區(qū)域。

因此告抄,在這種情況下撰茎,您將在最終調(diào)用drawLinearGradient(_:start:end:options :)繪制漸變之前,在上下文和剪輯上設(shè)置提供的矩形打洼。

是時候給這個方法一個旋轉(zhuǎn)龄糊!打開StarshipsListCellBackground.swift,在獲取當前的UIGraphicsContext之后募疮,用以下內(nèi)容替換代碼:

let backgroundRect = bounds
context.drawLinearGradient(
  in: backgroundRect, 
  startingWith: UIColor.starwarsSpaceBlue.cgColor, 
  finishingWith: UIColor.black.cgColor
)

構(gòu)建并運行

您現(xiàn)在已成功將漸變背景添加到自定義單元格绎签。 干得好,但是酝锅,可以公平地說诡必,現(xiàn)在成品并不是很好看。 是時候用一些標準的UIKit主題來修復(fù)它了。


Fixing the Theme

打開Main.storyboard并選擇Master scene中的表格視圖爸舒。 在“屬性”檢查器中蟋字,將Separator設(shè)置為None

然后扭勉,在Master Navigation Controller場景中選擇Navigation Bar并將導(dǎo)航欄樣式設(shè)置為黑色并取消選擇半透明(Translucent)鹊奖。 在Detail Navigation Controller場景中重復(fù)Navigation Bar

接下來涂炎,打開MasterViewController.swift忠聚。 在viewDidLoad()的末尾,添加以下內(nèi)容:

tableView.backgroundColor = .starwarsSpaceBlue

然后在tableView(_:cellForRowAt :)中唱捣,在返回單元格之前两蟀,設(shè)置文本的顏色:

cell.textLabel!.textColor = .starwarsStarshipGrey

最后,打開AppDelegate.swift并在application(_:didFinishLaunchingWithOptions:)中返回之前添加以下內(nèi)容:

// Theming
UINavigationBar.appearance().tintColor = .starwarsYellow
UINavigationBar.appearance().barTintColor = .starwarsSpaceBlue
UINavigationBar.appearance().titleTextAttributes = 
  [.foregroundColor: UIColor.starwarsStarshipGrey]

構(gòu)建并運行

那更好震缭!您的主表視圖開始看起來非常太空赂毯。


Stroking Paths

Core Graphics中進行描邊意味著沿著路徑繪制一條線,而不是像之前那樣填充它拣宰。

Core Graphics描繪路徑時党涕,它會在路徑的精確邊緣的中間繪制描邊線。這可能會導(dǎo)致一些常見問題巡社。

1. Outside the Bounds

首先膛堤,如果您正在繪制一個矩形的邊緣,例如晌该,邊框骑祟,默認情況下,Core Graphics將不會繪制一半的描邊路徑气笙。

為什么次企?因為為UIView設(shè)置的上下文僅擴展到視圖的邊界。想象一下潜圃,在視圖邊緣周圍有一個點邊框缸棵。因為Core Graphics在路徑的中間向下劃線,所以該線將在視圖邊界之外半個點谭期,在視圖邊界內(nèi)半個點堵第。

一個常見的解決方案是將行程的路徑插入每個方向的線寬度的一半,使其位于視圖內(nèi)隧出。

下圖顯示了一個黃色矩形踏志,在灰色背景上有一個點寬的紅色描邊,以一個點間隔條紋胀瞪。在左圖中针余,描邊路徑遵循視圖的邊界并已被裁剪饲鄙。您可以看到這一點,因為紅線是灰色方塊寬度的一半圆雁。在右圖中忍级,描邊路徑已插入半個點的間隔,現(xiàn)在具有正確的線寬伪朽。

2. Anti-Aliasing

其次轴咱,您需要了解可能影響邊框外觀的抗鋸齒效果。消除鋸齒烈涮,如果您不熟悉它(即使您可能在計算機游戲設(shè)置屏幕上聽說過它F臃巍),也是一種渲染引擎用于避免在顯示圖形時出現(xiàn)“鋸齒狀”邊緣和線條的技術(shù)不要完美映射到設(shè)備上的物理像素坚洽。

以前一段視圖周圍的一點邊框為例戈稿。如果邊框遵循視圖的邊界,則Core Graphics將嘗試在矩形的任一側(cè)繪制半個點寬的線酪术。

在非視網(wǎng)膜顯示器上,一個點等于設(shè)備上的一個像素翠储。不可能只照亮一半像素绘雁,因此Core Graphics將使用消除鋸齒來繪制兩個像素,但是在較淺的陰影中只能呈現(xiàn)單個像素的外觀援所。

在以下幾組屏幕截圖中庐舟,左圖像是非視網(wǎng)膜顯示器,中間圖像是視網(wǎng)膜顯示器住拭,其比例為2挪略,第三圖像是視網(wǎng)膜顯示器,其比例為3滔岳。

對于第一個圖杠娱,請注意2x圖像如何不顯示任何抗鋸齒,因為黃色矩形的兩邊的半點落在像素邊界上谱煤。然而摊求,在1x和3x圖像中發(fā)生抗鋸齒。

在下一組屏幕截圖中刘离,描邊矩形已插入半個點間隔室叉,使得筆劃線與點精確對齊,從而與像素邊界對齊硫惕。 注意沒有鋸齒偽像茧痕。


Adding a Border

回到你的應(yīng)用程序! cell開始看起來很好恼除,但你會增加另一種觸感踪旷,讓它們脫穎而出。 這一次,你將在cell邊緣繪制一個明亮的黃色框埃脏。

您已經(jīng)知道如何輕松填充矩形搪锣。 好吧,在他們周圍描邊也同樣容易彩掐。

打開StarshipsListCellBackground.swift并將以下內(nèi)容添加到draw(_ :)的底部:

let strokeRect = backgroundRect.insetBy(dx: 4.5, dy: 4.5)
context.setStrokeColor(UIColor.starwarsYellow.cgColor)
context.setLineWidth(1)
context.stroke(strokeRect)

在這里构舟,您可以創(chuàng)建一個用于描邊的矩形,它在x和y方向上從背景矩形中插入4.5個點堵幽。 然后將描邊顏色設(shè)置為黃色狗超,將線寬設(shè)置為一個點,最后描邊矩形朴下。 構(gòu)建并運行您的項目努咐。

現(xiàn)在你的星艦列表真的看起來像是來自遙遠的星系!


Building a Card Layout

雖然你的主視圖控制器看起來很花哨殴胧,但細節(jié)視圖控制器仍然需要一些修飾渗稍!

對于此視圖,您將首先使用自定義UITableView子類在表視圖背景上繪制漸變团滥。

創(chuàng)建一個名為StarshipTableView.swift的新Swift文件竿屹。 用以下內(nèi)容替換生成的代碼:

import UIKit

class StarshipTableView: UITableView {
  override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else {
      return
    }

    let backgroundRect = bounds
    context.drawLinearGradient(
      in: backgroundRect, 
      startingWith: UIColor.starwarsSpaceBlue.cgColor, 
      finishingWith: UIColor.black.cgColor
    )
  }
}

現(xiàn)在這應(yīng)該開始變得熟悉了。 在新表視圖子類的draw(_ :)方法中灸姊,您將獲得當前的CGContext拱燃,然后在視圖的邊界繪制一個漸變,從頂部的藍色開始力惯,在底部朝向黑色碗誉。 簡單!

打開Main.storyboard并單擊Detail場景中的TableView父晶。 在Identity檢查器中哮缺,將類設(shè)置為新的StarshipTableView

構(gòu)建并運行應(yīng)用程序甲喝,然后點擊X-wing那一行 蝴蜓。

您的詳細視圖現(xiàn)在具有從上到下運行的漂亮的全屏漸變,但表格視圖中的單元格遮擋了效果的最佳部分俺猿。 是時候解決這個問題并為細節(jié)cell添加更多的天賦茎匠。

回到Main.storyboard,在Detail Scene中選擇FieldCell押袍。 在“屬性”檢查器中诵冒,將背景設(shè)置為Clear Color。 接下來谊惭,打開DetailViewController.swift汽馋,在tableView(_:cellForRowAt :)的最底部首装,在返回單元格之前蕾总,添加以下內(nèi)容:

cell.textLabel!.textColor = .starwarsStarshipGrey
cell.detailTextLabel!.textColor = .starwarsYellow

這只是將單元格的字段名稱和值設(shè)置為適合星球大戰(zhàn)主題的更合適的顏色收苏。

然后台诗,在tableView(_:cellForRowAt :)之后添加以下方法來設(shè)置表視圖頭的樣式:

override func tableView(
  _ tableView: UITableView, 
  willDisplayHeaderView view: UIView, 
  forSection section: Int
) {
    view.tintColor = .starwarsYellow
    if let header = view as? UITableViewHeaderFooterView {
      header.textLabel?.textColor = .starwarsSpaceBlue
    }
  }

在這里,您將表格視圖的標題視圖的色調(diào)顏色設(shè)置為主題黃色铁蹈,為其提供黃色背景宽闲,并將其文本顏色設(shè)置為主題藍色。


Drawing Lines

作為bling的最后一點握牧,您將在詳細視圖中為每個單元格添加一個拆分器容诬。 創(chuàng)建一個新的Swift文件,這次稱為YellowSplitterTableViewCell.swift沿腰。 用以下內(nèi)容替換生成的代碼:

import UIKit

class YellowSplitterTableViewCell: UITableViewCell {
  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()
  }
}

YellowSplitterTableVIewCell中览徒,您使用Core Graphics來劃分單元格邊界底部的一條線。 注意所使用的y值是如何比視圖的邊界小半個點颂龙,以確保分割器完全在單元內(nèi)繪制习蓬。

現(xiàn)在,您需要實際繪制顯示拆分器的線措嵌。

要在A和B之間繪制一條線躲叼,首先移動到A點,這不會導(dǎo)致Core Graphics繪制任何東西铅匹。 然后押赊,您將一條線添加到B點饺藤,該線將點A到點B的線添加到上下文中包斑。 然后,您可以調(diào)用strokePath()來描邊該行涕俗。

最后罗丰,再次打開Main.storyboard并使用Identity檢查器將Detail場景中的FieldCell類設(shè)置為新創(chuàng)建的YellowSplitterTableViewCell。 構(gòu)建并運行您的應(yīng)用程序再姑。 然后萌抵,打開X-wing細節(jié)視圖。 漂亮元镀!

后記

本篇主要講述了Lines, Rectangles 和 Gradients绍填,感興趣的給個贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市栖疑,隨后出現(xiàn)的幾起案子讨永,更是在濱河造成了極大的恐慌,老刑警劉巖遇革,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卿闹,死亡現(xiàn)場離奇詭異揭糕,居然都是意外死亡,警方通過查閱死者的電腦和手機锻霎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門著角,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旋恼,你說我怎么就攤上這事吏口。” “怎么了蚌铜?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵锨侯,是天一觀的道長。 經(jīng)常有香客問我冬殃,道長囚痴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任审葬,我火速辦了婚禮深滚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涣觉。我一直安慰自己痴荐,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布官册。 她就那樣靜靜地躺著生兆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膝宁。 梳的紋絲不亂的頭發(fā)上鸦难,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音员淫,去河邊找鬼合蔽。 笑死,一個胖子當著我的面吹牛介返,可吹牛的內(nèi)容都是我干的拴事。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼圣蝎,長吁一口氣:“原來是場噩夢啊……” “哼刃宵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起徘公,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤牲证,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后步淹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體从隆,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡诚撵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了键闺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寿烟。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辛燥,靈堂內(nèi)的尸體忽然破棺而出筛武,到底是詐尸還是另有隱情,我是刑警寧澤挎塌,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布徘六,位于F島的核電站,受9級特大地震影響榴都,放射性物質(zhì)發(fā)生泄漏待锈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一嘴高、第九天 我趴在偏房一處隱蔽的房頂上張望竿音。 院中可真熱鬧,春花似錦拴驮、人聲如沸春瞬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宽气。三九已至,卻和暖如春潜沦,著一層夾襖步出監(jiān)牢的瞬間萄涯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工止潮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留窃判,地道東北人钞楼。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓喇闸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親询件。 傳聞我的和親對象是個殘疾皇子燃乍,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容