Gradients

Quartz為創(chuàng)建漸變提供了CGShadingRef和CGGradientRef兩種不透明的數(shù)據(jù)類型。您可以使用其中任一種創(chuàng)建軸向或徑向漸變。漸變是從一種顏色到另一種顏色變化的填充。

軸向梯度(也稱為線性梯度)沿著兩個限定的端點之間的軸線變化。位于與軸垂直的線上的所有點具有相同的顏色值。

徑向梯度是沿兩個限定端之間的軸徑向變化的填充,其通常都是圓。如果點位于中心點落在軸上的圓的圓周上,則點共享相同的顏色值。梯度的圓形部分的半徑由端圓的半徑限定;每個中間圓的半徑從一端到另一端線性地變化。

本章提供了可以使用Quartz創(chuàng)建的線性和徑向漸變的示例,比較可以對繪制漸變進行影響的兩種方法,然后展示如何使用每個不透明數(shù)據(jù)類型創(chuàng)建漸變。

軸向和徑向梯度示例

Quartz函數(shù)為創(chuàng)建梯度效果提供了豐富的詞匯。 此部分顯示您可以實現(xiàn)的一些結(jié)果。 圖8-1中的軸向梯度在作為橙色的一個端點和作為黃色的另一個端點之間變化。 在這種情況下,軸相對于原點成45度角。

8-1 沿45度軸的軸向梯度

Quartz還允許您指定沿軸的顏色和位置,以創(chuàng)建更復雜的軸向漸變,如圖8-2所示。 起點處的顏色是紅色的陰影,終點處的顏色是紫色的陰影。 但是,軸上也有五個位置,其顏色分別設置為橙色,黃色,綠色,藍色和靛藍。 您可以將結(jié)果視為沿著同一軸的六個連續(xù)線性漸變。 盡管這里使用的軸與圖8-1(45度角)中使用的軸相同,但它不一定是。 軸的角度由您提供的起點和終點定義。

8-2 用七個位置和顏色創(chuàng)建的軸向漸變

圖8-3顯示了一個小的,明亮的紅色圓圈和一個較大的黑色圓圈之間變化的徑向梯度。

8-3 在兩個圓之間變化的徑向梯度

使用Quartz,您不僅限于基于顏色更改創(chuàng)建漸變; 您可以只改變alpha,或者你可以改變alpha與其他顏色組件。 圖8-4顯示了一個梯度,其中紅色,綠色和藍色分量保持恒定,因為alpha值從1.0變化到0.1。

注:如果使用alpha更改漸變,則在繪制到PDF內(nèi)容時將無法捕獲該漸變。 因此,不能打印這種梯度。 如果你需要繪制一個梯度到PDF,使用1.0的alpha。

8-4 通過僅改變alpha分量創(chuàng)建的徑向梯度

您可以將圓形放置在徑向漸變中以創(chuàng)建各種形狀。 如果一個圓的一部分或全部在另一個圓外,Quartz為具有不相等周長的圓形創(chuàng)建一個圓錐形表面,并為具有相等圓周的圓形創(chuàng)建一個圓柱形表面。 徑向漸變的常見用法是創(chuàng)建一個陰影球體,如圖8-5所示。 在這種情況下,單個點(半徑為0的圓)位于較大的圓內(nèi)。

8-5 在點和圓之間變化的徑向梯度

您可以通過嵌套多個徑向漸變創(chuàng)建更復雜的效果,類似于圖8-6所示的形狀。 使用同心圓創(chuàng)建形狀的環(huán)形部分。

8-6 嵌套徑向漸變

CGShading和CGGradient對象的比較

有兩種類型的對象可用于創(chuàng)建漸變,你可能想知道最好使用哪一個。本節(jié)有助于回答這個問題。

CGShadingRef opaque數(shù)據(jù)類型使您可以控制如何計算漸變中每個點的顏色。在創(chuàng)建CGShading對象之前,必須創(chuàng)建一個CGFunction對象(CGFunctionRef),該對象定義用于計算漸變中顏色的函數(shù)。編寫自定義函數(shù)可以自由創(chuàng)建平滑漸變,例如圖8-1,圖8-3和圖8-5所示的平滑漸變或更多非常規(guī)效果,如圖8-12所示。

當創(chuàng)建CGShading對象時,您可以指定它是軸向(線性)還是徑向。除了梯度計算功能(封裝為CGFunction對象),您還可以提供顏色空間,以及起點和終點或半徑,具體取決于是繪制軸向還是徑向漸變。在繪制時,您只需將CGShading對象與繪圖上下文一起傳遞給函數(shù)CGContextDrawShading。 Quartz為漸變中的每個點調(diào)用你的梯度計算函數(shù)。

CGGradient對象是CGShading對象的一個??子集,它的設計考慮了易用性。 CGGradientRef不透明數(shù)據(jù)類型是直接使用,因為Quartz計算梯度中每個點的顏色 - 你不提供梯度計算功能。當您創(chuàng)建漸變對象時,您將提供一個位置和顏色的數(shù)組。 Quartz為每組連續(xù)位置計算一個漸變,使用您分配給每個位置的顏色作為漸變的終點。您可以將漸變對象設置為使用單個開始和結(jié)束位置,如圖8-1所示,或者您可以提供多個點來創(chuàng)建類似于圖8-2所示的效果。提供多于兩個位置的能力是優(yōu)于使用CGShading對象的優(yōu)點,其限于兩個位置。

當創(chuàng)建CGGradient對象時,您只需為每個位置設置一個顏色空間,位置和顏色。當使用漸變對象繪制到上下文時,可以指定Quartz是否應繪制軸向或徑向漸變。在繪制時,您可以指定起點和終點或半徑,具體取決于是繪制軸向還是徑向漸變,而CGShading對象的幾何是在創(chuàng)建時定義的,而不是在繪制時。

表8-1總結(jié)了兩種不透明數(shù)據(jù)類型之間的差異。

CGShading和CGGradient對象之間的差異

Extending Color Beyond the End of a Gradient

當您創(chuàng)建漸變時,您可以選擇用純色填充超出漸變末端的空間。 Quartz使用在漸變邊界定義的顏色作為填充顏色。 您可以延伸超出漸變的開始,漸變的結(jié)束,或兩者。 您可以將選項應用于使用CGShading對象或CGGradient對象創(chuàng)建的軸向或徑向漸變。 每種類型的對象都提供常量,您可以使用它來設置擴展選項,您將在使用CGGradient對象和使用CGShading對象中看到。

圖8-7顯示了在開始和結(jié)束位置延伸的軸向梯度。 圖中的線顯示了漸變的軸。 如您所見,填充顏色對應于起點和終點處的顏色。

8-7 延伸軸向梯度

圖8-8比較了不使用擴展選項的徑向漸變和對開始和結(jié)束位置使用擴展選項的漸變。 Quartz獲取開始和結(jié)束顏色值,并使用這些純色來擴展曲面,如圖所示。 該圖顯示了起始和結(jié)束圓形以及漸變的軸。

8-8 擴展徑向漸變

使用CGGradient對象

CGGradient對象是漸變的抽象定義 - 它僅僅指定顏色和位置,而不是幾何。您可以將這個相同的對象用于軸向和徑向幾何。作為抽象定義,CGGradient對象可能比它們的對應CGShading對象更容易重用。沒有在CGGradient對象中鎖定幾何體允許基于相同的顏色方案迭代地繪制梯度的可能性,而不需要也在多個CGGradient對象中占用存儲器資源。

因為Quartz為你計算梯度,使用CGGradient對象來創(chuàng)建和繪制梯度是相當簡單的,需要以下步驟:

  1. 創(chuàng)建一個CGGradient對象,提供一個顏色空間,兩個或多個顏色組件的數(shù)組,兩個或多個位置的數(shù)組,以及每個數(shù)組中的項目數(shù)。
  2. 通過調(diào)用CGContextDrawLinearGradient或CGContextDrawRadialGradient并提供上下文,CGGradient對象,繪圖選項,以及說明和結(jié)束幾何(點為軸向梯度或圓心和徑向漸變的半徑)繪制漸變。
  3. 當不再需要CGGradient對象時,釋放它。

位置是在0.0到1.0(包括1和0.0)范圍內(nèi)的CGFloat值,其指定沿著梯度的軸的歸一化距離。值0.0指定軸的起點,而1.0指定軸的終點。其他值指定距離的一部分,例如,距起點的四分之一距離為0.25,軸上的中間點為0.5。至少,Quartz使用兩個位置。如果為locations數(shù)組傳遞NULL,Quartz對第一個位置使用0,對第二個位置使用1。

每種顏色的顏色分量的數(shù)量取決于顏色空間。對于屏幕上的繪圖,您將使用RGB顏色空間。因為Quartz使用alpha繪制,每個屏幕上的顏色有四個組件 - 紅色,綠色,藍色和alpha。因此,對于屏幕上的繪圖,您提供的顏色組件數(shù)組中的元素數(shù)量必須包含位置數(shù)量的四倍。石英RGBA顏色分量的值可以從0.0到1.0(含)不等。

清單8-1是一個創(chuàng)建CGGradient對象的代碼片段。在聲明必要的變量之后,代碼設置位置和必需數(shù)量的顏色分量(在本例中為2×4 = 8)。它創(chuàng)建一個通用的RGB顏色空間。 (在iOS中,通用的RGB顏色空間不可用,你的代碼應該調(diào)用CGColorSpaceCreateDeviceRGB)然后,它傳遞必要的參數(shù)到CGGradientCreateWithColorComponents函數(shù)。你也可以使用函數(shù)CGGradientCreateWithColors,如果你的應用程序設置CGColor對象,這很方便。

// 創(chuàng)建一個CGGradient對象
CGGradientRef myGradient;
CGColorSpaceRef myColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 0.5, 0.4, 1.0,  // Start color
                          0.8, 0.8, 0.3, 1.0 }; // End color
 
myColorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
myGradient = CGGradientCreateWithColorComponents (myColorspace, components,
                          locations, num_locations);

創(chuàng)建CGGradient對象后,可以使用它繪制軸向或線性漸變。 清單8-2是一個代碼片段,它聲明并設置線性漸變的起點和終點,然后繪制漸變。 結(jié)果如圖8-1所示。 代碼不顯示如何獲取CGContext對象(myContext)。

// 使用CGGradient對象繪制軸向漸變
CGPoint myStartPoint, myEndPoint;
myStartPoint.x = 0.0;
myStartPoint.y = 0.0;
myEndPoint.x = 1.0;
myEndPoint.y = 1.0;
CGContextDrawLinearGradient (myContext, myGradient, myStartPoint, myEndPoint, 0);

清單8-3是一個代碼片段,它使用清單8-1中創(chuàng)建的CGGradient對象來繪制如圖8-9所示的徑向漸變。 本示例說明了通過用純色填充來擴展?jié)u變區(qū)域的結(jié)果。

// 使用CGGradient對象繪制徑向漸變
CGPoint myStartPoint, myEndPoint;
CGFloat myStartRadius, myEndRadius;
myStartPoint.x = 0.15;
myStartPoint.y = 0.15;
myEndPoint.x = 0.5;
myEndPoint.y = 0.5;
myStartRadius = 0.1;
myEndRadius = 0.25;
CGContextDrawRadialGradient (myContext, myGradient, myStartPoint,
                         myStartRadius, myEndPoint, myEndRadius,
                         kCGGradientDrawsAfterEndLocation);
8-9 使用CGGradient對象繪制的徑向漸變

圖8-4中所示的徑向梯度是使用如清單8-4中所示的變量創(chuàng)建的。

// 用于通過改變alpha創(chuàng)建徑向梯度的變量
CGPoint myStartPoint, myEndPoint;
CGFloat myStartRadius, myEndRadius;
myStartPoint.x = 0.2;
myStartPoint.y = 0.5;
myEndPoint.x = 0.65;
myEndPoint.y = 0.5;
myStartRadius = 0.1;
myEndRadius = 0.25;
size_t num_locations = 2;
CGFloat locations[2] = { 0, 1.0 };
CGFloat components[8] = { 0.95, 0.3, 0.4, 1.0,
                          0.95, 0.3, 0.4, 0.1 };

清單8-5顯示了用于創(chuàng)建如圖8-10所示的灰度梯度的變量,它有三個位置。

// 用于創(chuàng)建灰色漸變的變量
size_t num_locations = 3;
CGFloat locations[3] = { 0.0, 0.5, 1.0};
CGFloat components[12] = {  1.0, 1.0, 1.0, 1.0,
                            0.5, 0.5, 0.5, 1.0,
                            1.0, 1.0, 1.0, 1.0 };
8-10 具有三個位置的軸向梯度

使用CGShading對象

您通過創(chuàng)建調(diào)用函數(shù)CGShadingCreateAxial或CGShadingCreateRadial來設置漸變對象CGShading,并提供以下參數(shù):

  • CGColorSpace對象,描述Quartz在解釋回調(diào)提供的顏色分量值時使用的顏色空間。
  • 起點和終點。 對于軸向梯度,這些是軸的開始和結(jié)束坐標(在用戶空間中)。 對于徑向漸變,這些是起始和結(jié)束圓的中心的坐標。
  • 用于定義漸變區(qū)域的圓的起始和終止半徑(僅適用于徑向漸變)。
  • 一個CGFunction對象,通過調(diào)用函數(shù)CGFunctionCreate獲得,將在本節(jié)后面討論。 這個回調(diào)例程必須返回一個在特定點繪制的顏色。
  • 布爾值,指定是使用純色填充起始點還是結(jié)束點以外的區(qū)域。

您提供給CGShading創(chuàng)建函數(shù)的CGFunction對象包含一個回調(diào)結(jié)構(gòu)以及Quartz實現(xiàn)回調(diào)所需的所有信息。也許設置CGShading對象最棘手的部分是創(chuàng)建CGFunction對象。當您調(diào)用函數(shù)CGFunctionCreate時,您提供以下:

  • 指向回調(diào)需要的任何數(shù)據(jù)的指針。
  • 回調(diào)的輸入值的數(shù)量。 Quartz要求您的回調(diào)需要一個輸入值。
  • 浮點值數(shù)組。 Quartz為你的回調(diào)提供了這個數(shù)組中的一個元素。輸入值的范圍從0到漸變開始處的顏色,到1,漸變結(jié)束處的顏色。
  • 您的回調(diào)提供的輸出值的數(shù)量。對于每個輸入值,回調(diào)必須為每個顏色分量提供一個值,并為alpha值指定不透明度。顏色分量值由Quartz在您創(chuàng)建的顏色空間中解釋并提供給CGShading創(chuàng)建函數(shù)。例如,如果使用RGB顏色空間,則提供值4作為輸出值(R,G,B和A)的數(shù)量。
  • 指定每個顏色分量和alpha值的浮點值數(shù)組。
  • 包含結(jié)構(gòu)版本(將此字段設置為0)的回調(diào)數(shù)據(jù)結(jié)構(gòu),用于生成顏色組件值的回調(diào)以及用于釋放在info參數(shù)中提供給回調(diào)的數(shù)據(jù)的可選回調(diào)。如果你命名你的回調(diào)myCalculateShadingValues,它將看起來像這樣:
    void myCalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)

創(chuàng)建CGShading對象后,如果需要,可以設置其他裁剪。 然后,調(diào)用函數(shù)CGContextDrawShading用漸變繪制上下文的裁剪區(qū)域。 當您調(diào)用此函數(shù)時,Quartz將調(diào)用您的回調(diào)以獲取跨越從起點到終點的范圍的顏色值。

當您不再需要CGShading對象時,您可以通過調(diào)用函數(shù)CGShadingRelease來釋放它。

使用CGShading對象繪制軸向漸變和使用CGShading對象繪制徑向漸變提供了編寫使用CGShading對象來繪制漸變的代碼的分步說明。

使用CGShading對象繪制軸向漸變

軸向和徑向梯度要求您執(zhí)行類似的步驟。 此示例顯示如何使用CGShading對象繪制軸向漸變,在圖形上下文中創(chuàng)建半圓形裁剪路徑,然后將漸變繪制到裁剪上下文以實現(xiàn)圖8-11所示的輸出。

8-11 一個軸向漸變,被剪切和繪制

要繪制圖中所示的軸向梯度,請按照這些部分中介紹的步驟操作:

  1. 設置CGFunction對象以計算顏色值
  2. 為軸向漸變創(chuàng)建一個CGShading對象
  3. 剪輯上下文
  4. 使用CGShading對象繪制軸向漸變
  5. 釋放對象
設置CGFunction對象以計算顏色值

您可以以任何方式計算顏色值,只要您的顏色計算函數(shù)有三個參數(shù):

  • void * info。 這是NULL或指向傳遞給CGShading創(chuàng)建函數(shù)的數(shù)據(jù)的指針。
  • const CGFloat * in。 Quartz將in數(shù)組傳遞給你的回調(diào)函數(shù)。 數(shù)組中的值必須在為CGFunction對象定義的輸入值范圍內(nèi)。 對于本示例,輸入范圍為0到1; 見清單8-7。
  • CGFloat * out。 你的回調(diào)將out數(shù)組傳遞給Quartz。 它在顏色空間中為每個顏色分量包含一個元素,以及一個alpha值。 輸出值應在為CGFunction對象定義的輸出值范圍內(nèi)。 對于本示例,輸出范圍為0到1; 見清單8-7。

有關這些參數(shù)的更多信息,請參閱CGFunctionEvaluateCallback。

清單8-6顯示了一個函數(shù),它通過將常量數(shù)組中定義的值乘以輸入值來計算顏色分量值。 因為輸入值范圍從0到1,所以輸出值的范圍從黑色(對于RGB,值0,0,0)到通過(1,0,.5),它是紫色色調(diào)。 請注意,最后一個組件始終設置為1,因此顏色始終完全不透明。

// 計算顏色分量值
static void myCalculateShadingValues (void *info,
                            const CGFloat *in,
                            CGFloat *out)
{
    CGFloat v;
    size_t k, components;
    static const CGFloat c[] = {1, 0, .5, 0 };
 
    components = (size_t)info;
 
    v = *in;
    for (k = 0; k < components -1; k++)
        *out++ = c[k] * v;
     *out++ = 1;
}

在編寫回調(diào)以計算顏色值之后,將其打包為CGFunction對象的一部分。 當你創(chuàng)建一個CGShading對象時,它是你提供給Quartz的CGFunction對象。 清單8-7顯示了一個創(chuàng)建CGFunction對象的函數(shù),該對象包含清單8-6中的回調(diào)。 每個編號的代碼行的詳細說明顯示在列表之后。

// 創(chuàng)建CGFunction對象
static CGFunctionRef myGetFunction (CGColorSpaceRef colorspace)// 1
{
    size_t numComponents;
    static const CGFloat input_value_range [2] = { 0, 1 };
    static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
    static const CGFunctionCallbacks callbacks = { 0,// 2
                                &myCalculateShadingValues,
                                NULL };
 
    numComponents = 1 + CGColorSpaceGetNumberOfComponents (colorspace);// 3
    return CGFunctionCreate ((void *) numComponents, // 4
                                1, // 5
                                input_value_range, // 6
                                numComponents, // 7
                                output_value_ranges, // 8
                                &callbacks);// 9
}

這里是代碼做了什么:

  1. 使用顏色空間作為參數(shù)。
  2. 聲明回調(diào)結(jié)構(gòu)并用結(jié)構(gòu)(0)的版本,顏色組件計算回調(diào)的指針以及可選發(fā)布函數(shù)的NULL填充它。
  3. 計算顏色空間中的顏色分量的數(shù)量,并將值增加1以計算Alpha值。
  4. 傳遞一個指向numComponents值的指針。此值由回調(diào)myCalculateShadingValues用于確定要計算的組件數(shù)。
  5. 指定1是回調(diào)的輸入值的數(shù)量。
  6. 提供一個數(shù)組,用于指定輸入的有效時間間隔。此數(shù)組包含0和1。
  7. 傳遞輸出值的數(shù)量,這是顏色分量的數(shù)量加上alpha。
  8. 提供一個數(shù)組,指定每個輸出值的有效間隔。此數(shù)組為每個組件指定間隔0和1.因為有四個組件,所以此數(shù)組中有八個元素。
  9. 傳遞一個指針到之前聲明和填充的回調(diào)結(jié)構(gòu)。
為軸向漸變創(chuàng)建一個CGShading對象

要創(chuàng)建一個CGShading對象,可以調(diào)用函數(shù)CGShadingCreateAxial,如清單8-8所示,傳遞一個顏色空間,起始點和結(jié)束點,一個CGFunction對象和一個布爾值,它指定是否填充開始和結(jié)束區(qū)域 點的漸變。

// 為軸向漸變創(chuàng)建CGShading對象
CGPoint     startPoint,
            endPoint;
CGFunctionRef myFunctionObject;
CGShadingRef myShading;
 
startPoint = CGPointMake(0,0.5);
endPoint = CGPointMake(1,0.5);
colorspace = CGColorSpaceCreateDeviceRGB();
myFunctionObject = myGetFunction (colorspace);
 
myShading = CGShadingCreateAxial (colorspace,
                        startPoint, endPoint,
                        myFunctionObject,
                        false, false)
剪輯上下文

當你繪制一個漸變,Quartz填充當前上下文。 繪制漸變與使用顏色和圖案不同,后者用于描畫和填充路徑對象。 因此,如果您希望漸變以特定形狀顯示,則需要相應地剪裁上下文。 清單8-9中的代碼為當前上下文添加了一個半圓,以便將漸變繪制到該剪裁區(qū)域中,如圖8-11所示。

如果你仔細看,你會注意到代碼應該導致一個半圓,而圖中顯示一個半橢圓。 為什么? 你會看到,當你看一下使用CGShading對象的軸向漸變的完整例程中的整個例程時,上下文也被縮放。 更多關于后面。 雖然您可能不需要在應用程序中應用縮放或剪輯,但Quartz 2D中存在這些和許多其他選項,以幫助您實現(xiàn)有趣的效果。

// 向圖形上下文中添加半圓剪輯
CGContextBeginPath (myContext);
    CGContextAddArc (myContext, .5, .5, .3, 0,
                    my_convert_to_radians (180), 0);
    CGContextClosePath (myContext);
    CGContextClip (myContext);
使用CGShading對象繪制軸向漸變

調(diào)用函數(shù)CGContextDrawShading以使用CGShading對象中指定的顏色漸變來填充當前上下文:

CGContextDrawShading (myContext, myShading);
釋放對象

當您不再需要CGShading對象時,您調(diào)用函數(shù)CGShadingRelease。 您還需要釋放CGColorSpace對象和CGFunction對象,如清單8-10所示。

// 釋放對象
CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);
使用CGShading對象的軸向漸變的完整例程

清單8-11中的代碼顯示了一個使用清單8-7中設置的CGFunction對象和清單8-6中所示的回調(diào)來繪制軸向漸變的完整例程。 每個編號的代碼行的詳細說明顯示在列表之后。

// 使用CGShading對象繪制軸向漸變
void myPaintAxialShading (CGContextRef myContext,// 1
                            CGRect bounds)
{
    CGPoint     startPoint,
                endPoint;
    CGAffineTransform myTransform;
    CGFloat width = bounds.size.width;
    CGFloat height = bounds.size.height;
 
 
    startPoint = CGPointMake(0,0.5); // 2
    endPoint = CGPointMake(1,0.5);// 3
 
    colorspace = CGColorSpaceCreateDeviceRGB();// 4
    myShadingFunction = myGetFunction(colorspace);// 5
 
    shading = CGShadingCreateAxial (colorspace, // 6
                                 startPoint, endPoint,
                                 myShadingFunction,
                                 false, false);
 
    myTransform = CGAffineTransformMakeScale (width, height);// 7
    CGContextConcatCTM (myContext, myTransform);// 8
    CGContextSaveGState (myContext);// 9
 
    CGContextClipToRect (myContext, CGRectMake(0, 0, 1, 1));// 10
    CGContextSetRGBFillColor (myContext, 1, 1, 1, 1);
    CGContextFillRect (myContext, CGRectMake(0, 0, 1, 1));
 
    CGContextBeginPath (myContext);// 11
    CGContextAddArc (myContext, .5, .5, .3, 0,
                        my_convert_to_radians (180), 0);
    CGContextClosePath (myContext);
    CGContextClip (myContext);
 
    CGContextDrawShading (myContext, shading);// 12
    CGColorSpaceRelease (colorspace);// 13
    CGShadingRelease (shading);
    CGFunctionRelease (myShadingFunction);
 
    CGContextRestoreGState (myContext); // 14
}

這里是代碼做了什么:

  1. 作為圖形上下文和要繪制的矩形的參數(shù)。
  2. 為起點分配一個值。該例程基于從0到1變化的用戶空間計算值。稍后,您將為Quartz繪制的窗口縮放空間。您可以將此坐標位置視為位于最左側(cè)的x和位于距離底部50%處的y。
  3. 為結(jié)束點指定值。您可以將此坐標位置視為位于最右側(cè)的x和距離底部50%的y。如您所見,漸變的軸是水平線。
  4. 為設備RGB創(chuàng)建顏色空間,因為此例程繪制到顯示。
  5. 通過調(diào)用如清單8-7所示的例程并傳遞剛剛創(chuàng)建的顏色空間來創(chuàng)建CGFunction對象。
  6. 為軸向漸變創(chuàng)建一個CGShading對象。最后兩個參數(shù)為false,表示Quartz不應填充起始點和結(jié)束點以外的區(qū)域。
  7. 設置仿射變換,其縮放到用于繪制的窗口的高度和寬度。注意,高度不一定等于寬度。在這個例子中,因為兩個不相等,所以最終結(jié)果是橢圓形而不是圓形。
  8. 將您剛剛設置的變換與傳遞給例程的圖形上下文相連接。
  9. 保存圖形狀態(tài),以便稍后恢復此狀態(tài)。
  10. 設置剪切區(qū)域。此行和下兩行將上下文剪切為以白色填充的矩形。效果是,漸變繪制到具有白色背景的窗口。
  11. 創(chuàng)建路徑。該線和接下來的三條線設置了半圓弧,并將其作為剪裁區(qū)域添加到圖形上下文中。效果是,漸變繪制到半圓的區(qū)域。然而,圓將被窗口的高度和寬度變換(參見步驟8),導致最終的效果是繪制到半橢圓的梯度。當窗口由用戶調(diào)整大小時,剪切區(qū)域被調(diào)整大小。
  12. 將漸變繪制到圖形上下文,如前所述轉(zhuǎn)換和裁剪漸變。
  13. 釋放對象。這一行和接下來的兩行釋放你創(chuàng)建的所有對象。
  14. 將圖形狀態(tài)恢復為在設置填充背景并剪切為半圈之前存在的狀態(tài)。恢復的狀態(tài)仍然由窗口的寬度和高度變換。

使用CGShading對象繪制徑向漸變

此示例顯示如何使用CGShading對象來產(chǎn)生如圖8-12所示的輸出。

8-12 使用CGShading對象創(chuàng)建的徑向漸變

要繪制徑向漸變,請按照以下部分中介紹的步驟操作:

  1. 設置CGFunction對象以計算顏色值。
  2. 為徑向漸變創(chuàng)建一個CGShading對象
  3. 使用CGShading對象繪制徑向漸變
  4. 釋放對象
設置CGFunction對象以計算顏色值

寫入函數(shù)用于計算徑向和軸向梯度的顏色值沒有區(qū)別。 事實上,您可以按照設置CGFunction對象以計算顏色值中的軸向漸變的說明進行操作。 清單8-12計算顏色,使顏色分量按正弦變化,一個周期基于函數(shù)中聲明的頻率值。 圖8-12中顯示的結(jié)果與圖8-11中顯示的顏色有很大不同。 盡管顏色輸出有所不同,但是代碼8-12中的代碼與代碼8-6相似,因為每個函數(shù)都遵循相同的原型。 每個函數(shù)接受一個輸入值并計算N個值,一個用于顏色空間的每個顏色分量,另一個用于Alpha值。

// 計算顏色分量值
static void  myCalculateShadingValues (void *info,
                                const CGFloat *in,
                                CGFloat *out)
{
    size_t k, components;
    double frequency[4] = { 55, 220, 110, 0 };
    components = (size_t)info;
    for (k = 0; k < components - 1; k++)
        *out++ = (1 + sin(*in * frequency[k]))/2;
     *out++ = 1; // alpha
}

回想一下,在寫入顏色計算函數(shù)之后,需要創(chuàng)建一個CGFunction對象,如設置CGFunction對象以計算顏色值中的軸值所述。

為徑向漸變創(chuàng)建一個CGShading對象

要創(chuàng)建一個CGShading對象或一個徑向漸變,你可以調(diào)用函數(shù)CGShadingCreateRadial,如代碼清單8-13所示,傳遞一個顏色空間,起始和結(jié)束點,半徑,起始和結(jié)束半徑,一個CGFunction對象和布爾值,以指定是否 填充超出漸變的起點和終點的區(qū)域。

// 為徑向漸變創(chuàng)建CGShading對象
CGPoint startPoint, endPoint;
    CGFloat startRadius, endRadius;
 
    startPoint = CGPointMake(0.25,0.3);
    startRadius = .1;
    endPoint = CGPointMake(.7,0.7);
    endRadius = .25;
    colorspace = CGColorSpaceCreateDeviceRGB();
    myShadingFunction = myGetFunction (colorspace);
    CGShadingCreateRadial (colorspace,
                    startPoint,
                    startRadius,
                    endPoint,
                    endRadius,
                    myShadingFunction,
                    false,
                    false);
使用CGShading對象繪制徑向漸變

調(diào)用函數(shù)CGContextDrawShading使用在CGShading對象中指定的指定顏色漸變填充當前上下文。

CGContextDrawShading (myContext, shading);

請注意,您使用相同的函數(shù)繪制漸變,無論漸變是軸向還是徑向。

釋放對象

當您不再需要CGShading對象時,您調(diào)用函數(shù)CGShadingRelease。 您還需要釋放CGColorSpace對象和CGFunction對象,如清單8-14所示。

// 釋放對象
CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);
使用CGShading對象繪制徑向漸變的完整例程

清單8-15中的代碼顯示了一個完整的例程,使用清單8-7中設置的CGFunction對象和清單8-12中所示的回調(diào)來繪制徑向漸變。 每個編號的代碼行的詳細說明顯示在列表之后。

// 使用CGShading對象繪制徑向漸變的例程
void myPaintRadialShading (CGContextRef myContext,// 1
                            CGRect bounds);
{
    CGPoint startPoint,
            endPoint;
    CGFloat startRadius,
            endRadius;
    CGAffineTransform myTransform;
    CGFloat width = bounds.size.width;
    CGFloat height = bounds.size.height;
 
    startPoint = CGPointMake(0.25,0.3); // 2
    startRadius = .1;  // 3
    endPoint = CGPointMake(.7,0.7); // 4
    endRadius = .25; // 5
 
    colorspace = CGColorSpaceCreateDeviceRGB(); // 6
    myShadingFunction = myGetFunction (colorspace); // 7
 
    shading = CGShadingCreateRadial (colorspace, // 8
                            startPoint, startRadius,
                            endPoint, endRadius,
                            myShadingFunction,
                            false, false);
 
    myTransform = CGAffineTransformMakeScale (width, height); // 9
    CGContextConcatCTM (myContext, myTransform); // 10
    CGContextSaveGState (myContext); // 11
 
    CGContextClipToRect (myContext, CGRectMake(0, 0, 1, 1)); // 12
    CGContextSetRGBFillColor (myContext, 1, 1, 1, 1);
    CGContextFillRect (myContext, CGRectMake(0, 0, 1, 1));
 
    CGContextDrawShading (myContext, shading); // 13
    CGColorSpaceRelease (colorspace); // 14
    CGShadingRelease (shading);
    CGFunctionRelease (myShadingFunction);
 
    CGContextRestoreGState (myContext); // 15
}

這里是代碼做了什么:

  1. 作為圖形上下文和要繪制的矩形的參數(shù)。
  2. 將值分配給起始圈的中心。該例程基于從0到1變化的用戶空間計算值。稍后,Quartz會繪制一個窗口來縮放空間。您可以將此坐標位置視為從左側(cè)25%處的x和從底部30%處的y。
  3. 分配起始圓的半徑。你可以認為這是用戶空間寬度的10%。
  4. 將值分配給結(jié)束圓的中心。您可以將此坐標位置視為從左側(cè)70%處的x和從底部70%處的y。
  5. 分配結(jié)束圓的半徑。你可以認為這是用戶空間寬度的25%。結(jié)束圓圈將大于起始圓圈。圓錐形將從左向右定向,向上傾斜。
  6. 為設備RGB創(chuàng)建顏色空間,因為此例程繪制到顯示。
  7. 通過調(diào)用如清單8-7所示的例程并傳遞剛剛創(chuàng)建的顏色空間來創(chuàng)建CGFunctionObject。但是,請記住,您將使用顏色計算函數(shù),如清單8-12所示。
  8. 為徑向漸變創(chuàng)建一個CGShading對象。最后兩個參數(shù)是false,表示Quartz不應該填充漸變的起點和終點以外的區(qū)域。
  9. 設置仿射變換,其縮放到用于繪制的窗口的高度和寬度。注意,高度不一定等于寬度。事實上,只要用戶調(diào)整窗口大小,轉(zhuǎn)換就會改變。
  10. 將您剛剛設置的變換與傳遞給例程的圖形上下文相連接。
  11. 保存圖形狀態(tài),以便稍后恢復此狀態(tài)。
  12. 設置剪切區(qū)域。此行和下兩行將上下文剪切為以白色填充的矩形。效果是,漸變繪制到具有白色背景的窗口。
  13. 將漸變繪制到圖形上下文,如前所述轉(zhuǎn)換漸變。
  14. 釋放對象。這一行和接下來的兩行釋放你創(chuàng)建的所有對象。
  15. 將圖形狀態(tài)恢復為在設置填充背景之前存在的狀態(tài)。恢復的狀態(tài)仍然由窗口的寬度和高度變換。

See Also

  • CGGradient Reference描述了創(chuàng)建CGGradient對象的函數(shù)。
  • CGShading Reference描述了創(chuàng)建CGShading對象的函數(shù)。
  • CGFunction Reference描述了計算CGShading對象的漸變顏色所需的函數(shù)。
  • CGContext Reference描述了使用CGGradient和CGShading對象繪制上下文的函數(shù)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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