iOS 圖形處理總結

iOS實現圖形編程可以使用三種API(UIKIT、Core Graphics、OpenGL ES及GLKit)。

這些api包含的繪制操作都在一個圖形環境中進行繪制。一個圖形環境包含繪制參數和所有的繪制需要的設備特定信息,包括屏幕圖形環境、offscreen 位圖環境和PDF圖形環境,用來在屏幕表面、一個位圖或一個pdf文件中進行圖形和圖像繪制。在屏幕圖形環境中進行的繪制限定于在一個UIView類或其子類的實例中繪制,并直接在屏幕顯示,在offscreen位圖或PDF圖形環境中進行的繪制不直接在屏幕上顯示。

一、UIKIT API

UIKIT是一組Objective-C API,為線條圖形、Quartz圖像和顏色操作提供Objective-C 封裝,并提供2D繪制、圖像處理及用戶接口級別的動畫。

UIKIT包括UIBezierPath(繪制線、角度、橢圓及其它圖形)、UIImage(顯示圖像)、UIColor(顏色操作)、UIFont和UIScreen(提供字體和屏幕信息)等類以及在位圖圖形環境、PDF圖形環境上進行繪制和 操作的功能等, 也提供對標準視圖的支持,也提供對打印功能的支持。

在UIKIT中UIView類本身在繪制時自動創建一個圖形環境(對應Core Graphics層的CGContext類型)作為當前的圖形繪制環境。在繪制時可以調用UIGraphicsGetCurrentContext 函數獲得當前的圖形環境。

二、Core Graphics 與Quartz 2D API

Core Graphics是一套C-based API, 支持向量圖形,線、形狀、圖案、路徑、剃度、位圖圖像和pdf 內容的繪制。

Quartz 2D 是Core Graphics中的2D 繪制呈現引擎。Quartz是資源和設備無關的,提供路徑繪制,anti-aliased呈現,剃度填充圖案,圖像,透明繪制和透明層、遮蔽和陰影、顏色管理,坐標轉換,字體、offscreen呈現、pdf文檔創建、顯示和分析等功能。

Quartz 2D能夠與所有的圖形和動畫技術(如Core Animation, OpenGL ES, 和 UIKit 等)一起使用。

Quartz采用paint模式進行繪制。

Quartz 中使用的圖形環境也由一個類CGContext表示。

在Quartz 中可以把一個圖形環境作為一個繪制目標。當使用Quartz 進行繪制時,所有設備特定的特性被包含在你使用的特定類型的圖形環境中,因此通過給相同的圖像操作函數提供不同的圖像環境你就能夠畫相同的圖像到不同的設備上,因此做到了圖像繪制的設備無關性。

Quartz 為應用提供如下幾個圖形環境:

1)位圖圖形環境,用來創建一個位圖。

使用函數CGBitmapContextCreate來創建。

2)PDF圖形環境,用來創建一個pdf文件。

Quartz 2D API提供了兩個函數來創建一個PDF圖形環境:

CGPDFContextCreateWithURL,帶有一個作為pdf 輸出的位置的Core Foundation URL來創建一個pdf 圖形環境。

CGPDFContextCreate, 當想PDF 輸出到一個data consumer時使用該函數。

3) 窗口圖形環境,用來在一個窗口上進行繪制。

4) 層環境(CGLayer) ,是一個與另一個圖形環境關聯的offscreen繪制目標,使用層環境的目的是為了優化繪制層到創建它的圖形環境的性能。層環境能夠比位圖圖形環境提供更好的offscreen繪制性能。

Quartz提供的主要類包括:

CGContext:表示一個圖形環境;

CGPath:使用向量圖形來創建路徑,并能夠填充和stroke;

CGImage:用來表示位圖;

CGLayer:用來表示一個能夠用于重復繪制和offscreen繪制的繪制層;

CGPattern:用來表示Pattern,用于重復繪制;

CGShading和 CGGradient:用于繪制剃度;

CGColor 和 CGColorSpace;用來進行顏色和顏色空間管理;

CGFont, 用于繪制文本;

CGPDFContentStream、CGPDFScanner、CGPDFPage、CGPDFObject,CGPDFStream, CGPDFString等用來進行pdf文件的創建、解析和顯示。

三、OpenGL ES和GLKit

OpenGL ES是一套多功能開放標準的用于嵌入系統的C-based的圖形庫,用于2D和3D數據的可視化。OpenGL被設計用來轉換一組圖形調用功能到底層圖形硬件(GPU),由GPU執行圖形命令,用來實現復雜的圖形操作和運算,從而能夠高性能、高幀率利用GPU提供的2D和3D繪制能力。

OpenGL ES規范本身不定義繪制表面和繪制窗口,因此ios為了使用它必須提供和創建一個OpenGLES 的呈現環境,創建和配置存儲繪制命令結果的framebuffer 及創建和配置一個或多個呈現目標。

在 iOS中使用EAGL提供的EAGLContext類 來實現和提供一個呈現環境,用來保持OpenGLES使用到的硬件狀態。 EAGL是一個Objective-C API,提供使OpenGL ES與Core Animation和UIKIT集成的接口。

在調用任何OpenGLES 功能之前必須首先初始化一個EAGLContext 對象。

每一個iOS應用的每一個線程都有一個當前context,在調用OpenGLES函數時,使用或改變此context中的狀態。

EAGLContext 的類方法setCurrentContext:用來設置當前線程的當前context。EAGLContext 的類方法currentContext 返回當前線程的當前context。在切換相同線程的兩個上下文之前,必須調用glFlush函數來確保先前已提交的命令被提交到圖形硬件中。

可以采用不同的方式使用OpenGL ES以便呈現OpenGL ES內容到不同的目標:GLKit和CAEAGLLayer。

為了創建全屏幕的視圖或使OpenGL ES內容與UIKit視圖集成,可以使用GLKit。在使用GLKit時,GLKit提供的類GLKView類本身實現呈現目標及創建和維護一個framebuffer。

為了使OpenGL ES內容作為一個Core Animation層的部分內容時,可以使用CAEAGLLayer 作為呈現目標,并需要另外創建framebuffer以及自己實現和控制整個繪制流程。

GLKit是一組Objective-C 類,為使用OpenGL ES 提供一個面向對象接口,用來簡化OpenGL ES應用的開發。GLKit支持四個3D應用開發的關鍵領域:

1) GLKView 和GLKViewController類提供一個標準的OpenGLES視圖和相關聯的呈現循環。GLKView可以作為OpenGLES內容的呈現目標,GLKViewController提供內容呈現的控制和動畫。視圖管理和維護一個framebuffer,應用只需在framebuffer進行繪畫即可。

2)GLKTextureLoader 為應用提供從iOS支持的各種圖像格式的源自動加載紋理圖像到OpenGLES 圖像環境的方式,并能夠進行適當的轉換,并支持同步和異步加載方式。

3)數學運算庫,提供向量、矩陣、四元數的實現和矩陣堆棧操作等OpenGL ES 1.1功能。

4)Effect效果類提供標準的公共著色效果的實現。能夠配置效果和相關的頂點數據,然后創建和加載適當的著色器。GLKit 包括三個可配置著色效果類:GLKBaseEffect實現OpenGL ES 1.1規范中的關鍵的燈光和材料模式, GLKSkyboxEffect提供一個skybox效果的實現, GLKReflectionMapEffect 在GLKBaseEffect基礎上包括反射映射支持。

使用GLKView和OpenGLES進行繪制過程:

1)創建一個GLKView 對象

GLKView 對象可以編程或使用Interface Builder來創建和配置。

在采用編程方式時,首先創建一個context然后調用initWithFrame:context:方法。

使用Interface Builder方式時,在從storyboard加載一個GLKView后,創建一個context和設置它作為視圖的context屬性.

在iOS中GLKit的使用需要創建OpenGL ES 2.0以上的圖形環境context。

GLKit視圖自動創建和配置它所有的OpenGLES framebuffer對象和renderbuffers,可以通過修改視圖的drawable屬性來控制這些對象的屬性。

2)繪制OpenGL內容(發布繪制命令)

使用GLKit視圖繪制OpenGL內容需要三個子步驟:準備OpenGLES基礎;發布繪制命令;呈現顯示內容到Core Animation。 GLKit類本身已經實現了第一個和第三個步驟,用戶只需實現第二個步驟,在視圖的方法drawRect或視圖的代理對象的glkView:drawInRect:中調用適當的OpenGLES繪制命令進行內容繪制。

GLKViewController類維護一個animation 呈現循環(包含兩個方法update和display),用來實現連續的動畫復雜的場景。

animation 呈現循環的交替速率由GLKViewController的屬性framesPerSecond 指示,并使用preferredFramesPerSecond 屬性來修改它。

四、其它圖形編程相關API

1)Core Animation

Core Animation是一套Objective-C API,實現了一個高性能的復合引擎,并提供一個簡單易用的編程接口,給用戶UI添加平滑運動和動態反饋能力。

Core Animation 是 UIKit實現動畫和變換的基礎,也負責視圖的復合功能。使用Core Animation可以實現定制動畫和細粒度的動畫控制,創建復雜的、支持動畫和變換的layered 2D視圖。

Core Animation不屬于繪制系統,但它是以硬件復合和操作顯示內容的基礎設施。這個基礎設施的核心是layer對象,用來管理和操作顯示內容。在ios 中每一個視圖都對應Core Animation的一個層對象,與視圖一樣,層之間也組織為層關系樹。一個層捕獲視圖內容為一個被圖像硬件容易操作的位圖。在多數應用中層作為管理視圖的方式使用,但也可以創建獨立的層到一個層關系樹中來顯示視圖不夠支持的顯示內容。

OpenGL ES的內容也可以與Core Animation內容進行集成。

為了使用Core Animation實現動畫,可以修改層的屬性值來觸發一個action對象的執行,不同的action對象實現不同的動畫。

Core Animation 提供了一下一組應用可以采用的類來提供對不同動畫類型的支持:

CAAnimation是一個抽象公共基類,CAAnimation采用CAMediaTiming 和CAAction協議為動畫提供時間(如周期、速度、重復次數等)和action行為(啟動、停止等)。

CAPropertyAnimation是 CAAnimation的抽象子類,為動畫提供一個由一個key路徑規定的層屬性的支持;

CABasicAnimation 是CAPropertyAnimation的具體子類,為一個層屬性提供簡單插入能力。

CAKeyframeAnimation也是CAPropertyAnimation的具體子類,提供key幀動畫支持。

CATransition是CAAnimation的具體子類,提供影響整個層內容的事物效果。

CAAnimationGroup也是CAAnimation的子類,允許動畫對象組合到一起并同時運行。

2)Image I/O

Image I/O 提供讀寫多數格式圖像文件的數據的接口。主要包括圖像源CGImageSourceRef和圖像目標CGImageDestinationRef兩個類。

3)Sprite Kit

Sprite Kit建立于OpenGL ES之上,Sprite Kit使用圖形硬件來有效的呈現動畫幀,因此可以高幀率地動畫和呈現任意的2D紋理圖像或游戲sprite,呈現的內容包括sprites、文本、CGPath形狀、視頻等。

在Sprite Kit中動畫和呈現由一個SKView視圖對象執行。游戲的內容組織為以SKScene對象表現的一個個場景。一個場景包含要呈現的sprites和其它內容,一個場景也實現每個幀關聯的邏輯和內容處理。

在同一時刻,一個SKView視圖只呈現一個場景,在場景呈現時,場景關聯的動畫和幀關聯的邏輯被自動執行。在切換場景時使用SKTransition 類來執行兩個場景間的動畫。

4)SceneKit

SceneKit是一個使用3D圖形技術實現的Objective-C 框架,包含一個高性能的呈現引擎和一個高級的描述性API。可以利用該框架創建簡單的游戲和界面豐富的用戶UI,使用SceneKit僅需要使用描述性API描述你的場景的內容(如幾何形狀、材料、燈光和攝像等)和你想在那些內容上要執行的行動或動畫即可。

SceneKit的內容組織為由節點組成的樹形結構,稱為scene graph。一個場景包含一個根節點,定義場景的坐標空間,其它節點定義場景的可視內容。SceneKit在GPU上呈現每一幀之前在一個視圖上顯示場景、處理scene graph和執行動畫處理。

SceneKit包含的主要類:

SCNView & SCNSceneRenderer:SCNView是顯示或呈現SceneKit內容的視圖。SCNSceneRenderer是一個協議,定義用于視圖的一些重要方法。

SCNScene: 表現一個場景,是所有SceneKit內容的一個容器。場景可以從使用3D著作工具創建的一個文件中加載,也可以編程創建,場景需要在一個視圖上顯示。

SCNNode:一個場景的基本構造塊,表示scene graph樹的一個節點。scene graph樹定義了場景上節點之間的邏輯結構,通過為一個節點附屬geometries、lights、cameras來提供場景的可視內容。

SCNGeometry、SCNLight、SCNCamera:分別是geometries、lights、cameras對應的類。SCNGeometry為場景提供形狀、文本或定制頂點數據,SCNLight為場景提供陰影效果,SCNCamera為場景提供可視點。

SCNMaterial:為SCNGeometry對象定義表面外觀屬性,規定對象表面如何著色或紋理以及如何反應燈光。

SceneKit內容的動畫:

SceneKit動畫基于Core Animation 框架,可以隱式或顯式創建。

隱式創建是實際是通過動畫節點的一些動畫屬性來實現:SceneKit自動在run loop一次運行期間對一個場景包含節點屬性的所有改變組合成一個原子操作,稱為一個事務,由SCNTransaction 類表示;當設置SCNTransaction類的動畫周期不為0時,所有對節點動畫屬性的改變自動執行動畫。

如下代碼片段所示:

func fallAndFade(sender: a href="" AnyObject /a ) {
SCNTransaction.setAnimationDuration(1.0)
textNode.position = SCNVector3(x: 0.0, y: -10.0, z: 0.0)
textNode.opacity = 0.0
}
顯式創建動畫時,可以選擇CAAnimation一種類型的子類來創建特定類型的動畫。使用key-value為動畫規定屬性及設置動畫參數,然后把創建的動畫附屬到場景的一個或多個元素。可以使用不同的Core Animation動畫類組合或序列化幾個動畫或創建動畫在幾個 keyframe值之間插入屬性值。

如下代碼片段為顯式創建動畫的例子:

let animation = CABasicAnimation(keyPath: "geometry.extrusionDepth")
animation.fromValue = 0.0
animation.toValue = 100.0
animation.duration = 1.0
animation.autoreverses = true
animation.repeatCount = Float.infinity
textNode.addAnimation(animation, forKey: “extrude")
SceneKit也支持使用SCNSceneSource 類從一個場景文件中加載CAAnimation動畫對象,然后附屬它到SCNNode對象。

5)Metal

Metal框架是一個OpenGL ES類似的底層API,為GPU加速的先進的3D圖形呈現或數據并行計算任務提供支持。Metal負責和3D繪圖硬件交互,為圖形和計算命令的組織、處理、提交和相關資源和數據的管理提供一個細粒度的、底層的支持流式計算的現代API。Metal的目標是在執行GPU任務時盡量減少CPU的負載,消除在GPU執行圖形和數據并行計算操作時的性能瓶頸,能夠有效的使用多線程并行創建和提交命令到GPU。

Metal也提供了一個映射編程語言用來編寫能夠被Metal應用使用的圖形映射或計算函數。Metal映射語言編寫的代碼能夠在編譯時與應用代碼一起被編譯,然后在運行時被加載到GPU上執行;也支持運行時對Metal 映射語言代碼進行編輯。

在Metal架構中包括如下幾個重要的類或協議:

1、MTLDevice協議和對象

一個MTLDevice代表一個執行命令的GPU設備,MTLDevice協議為其定義了相關接口,包括查詢設備能力屬性和創建其它設備特定的對象等接口,例如創建命令隊列、從內存中分配緩沖區以及創建紋理等。

應用通過調用MTLCreateSystemDefaultDevice 函數來獲取一個系統能夠使用的MTLDevice對象。

2、命令和命令編碼器

在Metal框架中,3D圖形呈現命令、計算命令和blitting命令在提交到特定設備GPU上執行前必須進行相應的格式編碼,以便能夠被GPU識別和執行。

Metal框架為每種命令提供了一種編碼器協議:

MTLRenderCommandEncoder 協議:提供接口用來編碼一個單次循環呈現期間要執行的3D圖形呈現命令。MTLRenderCommandEncoder 對象用來代表一次圖形呈現流程的呈現狀態和繪制命令。

MTLComputeCommandEncoder協議:提供接口用來編碼數據并行計算任務。

MTLBlitCommandEncoder協議:提供接口用來編碼在緩沖和紋理之間的簡單拷貝操作。

在同一時刻,僅能有一個命令編碼器激活來添加命令到一個命令緩沖空間上,即每一個命令編碼器必須在另一個使用相同命令緩沖空間的命令編碼器創建前結束。

Metal為了支持多個不同任務的并行執行,提供了一個MTLParallelRenderCommandEncoder協議來支持多個MTLBlitCommandEncoder在不同線程同時運行提交不同的命令緩沖到同一個命令緩沖空間。每一個線程有一個它自己的命令緩沖對象,在同一時刻,該緩沖對象只能被該線程的一個命令編碼器存取。

MTLParallelRenderCommandEncoder對象允許一次呈現循環的命令編碼分解到多個命令編碼器進行編碼,使用多線程進行并行處理來提高處理效率。

一個命令編碼器對象調用endEncoding方法來結束。

命令編碼器對象的創建:

命令編碼器對象由MTLCommandBuffer對象負責創建。MTLCommandBuffer協議定義了如下方法用來創建相應類型的命令編碼器對象:

renderCommandEncoderWithDescriptor:為執行圖形呈現任務創建一個MTLRenderCommandEncoder 對象。方法的參數MTLRenderPassDescriptor表現一個編碼呈現命令的目標(是一個附屬點的集合,最多可以包括四個顏色點數據附屬點、一個深度點數據附屬點、一個圖案點數據附屬點),在MTLRenderPassDescriptor對象的附屬點屬性中指定要呈現的圖形目標。

computeCommandEncoder方法為數據并行計算任務創建一個MTLComputeCommandEncoder 對象。

blitCommandEncoder 方法為內存Blit操作和紋理填充操及mipmaps的產生等操作創建一個MTLBlitCommandEncoder 對象。

parallelRenderCommandEncoderWithDescriptor: 方法創建一個MTLParallelRenderCommandEncoder對象。呈現目標由 參數MTLRenderPassDescriptor規定。

3、命令緩沖MTLCommandBuffer對象及協議

在經過命令編碼器編碼后的命令被命令編碼器添加到一個稱為命令緩沖的MTLCommandBuffer對象上,然后該CommandBuffer對象被提交到GPU來執行其中包含的命令。

MTLCommandBuffer協議為CommandBuffer對象定義接口以及提供命令編碼器的創建、提交CommandBuffer到一個命令隊列以及檢查狀態等操作方法。

一個CommandBuffer對象包含打算在特定設備(GPU)上執行的被編碼的命令。一旦所有的編碼完成,CommandBuffer本身必須提交到一個命令隊列,并標記命令緩沖為準備好狀態,以便能夠被GPU 執行。

在標準標準應用中,通常一個呈現幀的呈現命令使用一個線程被編碼進一個命令緩沖中。

MTLCommandBuffer對象的創建和相應方法:

一個MTLCommandBuffer對象由MTLCommandQueue的commandBuffer方法或commandBufferWithUnretainedReferences方法創建。

一個MTLCommandBuffer對象僅能提交到創建它的MTLCommandQueue 對象中。

一個MTLCommandBuffer對象還實現協議定義的如下方法:

enqueue方法用來在命令隊列中為該命令緩沖保留一個位置。

commit 方法使MTLCommandBuffer對象被提交執行。

addScheduledHandler:方法用來為一個命令緩沖對象登記一個在該命令緩沖被調度時被調用的代碼執行塊。可以為一個命令緩沖對象登記多個調度執行塊。

waitUntilScheduled 方法等待命令緩沖被調度及在為該命令緩沖登記的所有調度執行塊已經執行完。

addCompletedHandler:方法為一個命令緩沖對象登記一個在設備已經執行完該命令緩沖后被調用的代碼執行塊。也可以為一個命令緩沖對象登記多個完成執行代碼塊。

waitUntilCompleted 方法等待命令緩沖中命令被設備執行完和為該命令緩沖登記的所有完成執行塊都執行結束。

presentDrawable:方法用來在命令緩沖對象被調度時呈現一個可顯示資源(CAMetalDrawable 對象)的內容。

4、MTLCommandQueue協議和命令隊列對象

MTLCommandQueue協議為包含命令緩沖的一個隊列。命令隊列用來組織其中包含的命令緩沖對象的執行次序和控制命令隊列中的命令緩沖對象包含的命令什么時候被執行。

MTLCommandQueue協議為命令隊列定義了接口,主要的接口包括命令緩沖對象的創建。

MTLCommandQueue對象的創建:

使用MTLDevice對象的newCommandQueue方法或newCommandQueueWithMaxCommandBufferCount:方法來創建一個命令隊列對象。

下圖為以上這些對象之間的關系圖:

20141103175424013.jpg

如圖中所示:必須為一個呈現命令編碼器設置呈現相關的狀態、設置和創建相關的呈現用到的緩沖區、紋理等Metal資源對象。

為呈現命令編碼器指定的狀態包括一個呈現管道流水線狀態(Render Pipeline State),一個深度和圖案狀態(Depth Stencil State),一個采樣狀態(Sampler State)。

一個Blit命令編碼器與一個緩沖區和一個紋理關聯,用來在兩者之間進行Blit操作。

命令編碼器指定圖形或計算功能時可以分配三種類型的MTLResource Metal資源對象使用:

MTLBuffer 表現一個能夠包含任意類型數據的無格式內存。MTLBuffer通常用于多邊形頂點vertex、著色器shader及計算狀態數據。

MTLTexture表現一個有著特定紋理類型和點格式的具有相應格式的圖像數據。紋理對象可以作為多邊形頂點vertex、片段fragment或計算功能的一個源,也可以在呈現描述符中作為圖形呈現的輸出目標。

MTLSamplerState對象當一個圖形或計算功能在一個MTLTexture上執行紋理采樣操作時使用,用來定義地址、過濾和其它屬性。

圖形呈現編碼器MTLRenderCommandEncoder 可以使用setVertex及setFragment 方法組作為其參數來為相應的映射函數分配一個或多個資源。

5、CAMetalLayer 對象和CAMetalDrawable 協議

Core Animation定義了一個CAMetalLayer類和一個CAMetalDrawable 協議用來提供一個Metal內容呈現的層后備視圖。CAMetalLayer對象包含有關要呈現內容的位置、尺寸、可視屬性(背景顏色、邊界和陰影)及Metal呈現內容使用到的資源等。CAMetalDrawable 協議是MTLDrawable 的擴展,指定了可顯示資源對象要符合的MTLTexture協議,使可顯示資源對象可用作呈現命令的目標。

為了實現Metal內容在一個CAMetalLayer對象的呈現,應為每次呈現流程創建一個CAMetalDrawable對象,從中得到它包含的MTLTexture 對象,然后在呈現流水線描述MTLRenderPipelineDescriptor 的顏色附屬點屬性中使用,指定其為圖形呈現命令的目標。

一個CAMetalLayer對象調用CAMetalLayer 對象的nextDrawable 方法來創建。

在創建一個可顯示資源作為圖形命令的目標后,就可以調用如下步驟完成圖形的繪制。

1)、首先創建一個MTLCommandQueue 對象,然后使用它創建一個MTLCommandBuffer對象;

2)、創建一個MTLRenderPassDescriptor對象,為其規定用作圖形緩沖中的編碼呈現命令目標的附屬點集合;然后使用這個MTLRenderPassDescriptor 對象創建一個MTLRenderCommandEncoder對象;

3) 創建相應的Metal資源對象,來存儲繪制用到資源數據,如頂點坐標和頂點顏色數據;并調用MTLRenderCommandEncoder的setVertex:offset:atIndex: 和setFragment :offset:atIndex:方法來為呈現編碼器指定用到的資源;

4) 創建一個MTLRenderPipelineDescriptor 對象并為其指定vertexFunction和fragmentFunction 屬性,這些屬性使用Metal映射語言代碼中讀取的相應映射函數MTLFunction對象來設置。

5)使用MTLDevice的newRenderPipelineStateWithDescriptor:error:方法或類似方法并根據MTLRenderPipelineDescriptor創建一個MTLRenderPipelineState對象;然后調用MTLRenderCommandEncoder 的setRenderPipelineState: 方法來為呈現編碼器對象MTLRenderCommandEncoder設置管道流水線;

6)調用MTLRenderCommandEncoder 的drawPrimitives:vertexStart:vertexCount: 方法來執行圖形的呈現,然后調用MTLRenderCommandEncoder的endEncoding 方法來結束本次呈現流程的編碼,最后調用MTLCommandBuffer 的commit方法來在GPU上執行整個繪制命令。

http://www.cocoachina.com/ios/20141104/10124.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容

  • iOS實現圖形編程可以使用三種API(UIKIT、Core Graphics、OpenGL ES及GLKit)。 ...
    亦珩閱讀 709評論 1 2
  • 看到的一篇圖形開發的博客,搬了過來記錄一下,慢慢學習 轉載原博地址 iOS實現圖形編程可以使用三種API(UIKI...
    LanWor閱讀 1,102評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,659評論 25 708
  • 有想法去減肥,是在去年10月份開始的,算算到現在已經過去7個多月了,按說,如果我真的能夠做到合理飲食、積極鍛煉,現...
    媌世界閱讀 310評論 0 2
  • 怦然心動?有過的太奢侈
    _綠子閱讀 195評論 0 0