CoreAnimation編程指南(五)圖層內容

轉載自 http://www.dreamingwish.com/dream-2012/coreanimation-programming-guide-e-the-content-layer.html

當我們使用Cocoa的視圖的時候,我們必須繼承NSView或者UIView並且重載函數drawRect:來顯示任何內容。但是CALayer實例可以直接使用,而無需繼承子類。因爲CALayer是一個鍵-值編碼兼容的容器類,你可以在實例裏面存儲任意值,所以子類實例化完全可以避免。

1.1 給CALayer提供內容

你可以通過以下任何一種方法指定CALayer實例的內容:

  • 使用包含圖片內容的CGImageRef來顯式的設置圖層的contents的屬性。
  • 指定一個委託,它提供或者重繪內容。
  • 繼承CALayer類重載顯示的函數。

1.1.1 設置contents屬性

圖層的圖片內容可以通過指定contents屬性的值爲CGImageRef。當圖層被創建的時候或者在任何其他時候,這個操作可以在其他實體上面完成(如表3所示)。

代碼 1  設定layer的contents屬性

CALayer *theLayer;

// create the layer and set the bounds and position
theLayer=[CALayer layer];
theLayer.position=CGPointMake(50.0f,50.0f);
theLayer.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f);

// set the contents property to a CGImageRef
// specified by theImage (loaded elsewhere)
theLayer.contents=theImage;

 

 

1.1.2 通過委託提供內容

你可以繪製圖層的內容,或更好的封裝圖層的內容圖片,通過創建一個委託類實現下列方法之一:

displayLayer:或drawLayer:inContext:

實現委託重繪的方法並不意味會自動的觸發圖層使用實現的方法來重繪內容。而是你要顯式的告訴一個圖層實例來重新緩存內容,通過發送以下任何一個方法setNeedsDisplay或者setNeedsDisplayInRect:的消息,或者把圖層的needsDisplayOnBoundsChange屬性值設置爲YES。

通過委託實現方法displayLayer:可以根據特定的圖層決定顯示什麼圖片,還可以更加需要設置圖層的contents屬性值。下面的例子是“圖層的座標系”部分的,它實現displayerLayer:方法根據state的值設置theLayer的contents屬性。子類不需要存儲state的值,因爲CALayer的實例是一個鍵-值編碼容器。

代碼 2  委託方法displayLayer:的實現示例

- (void)displayLayer:(CALayer *)theLayer
{
    // check the value of the layer's state key
    if ([[theLayer valueForKey:@"state"] boolValue])
    {
        // display the yes image
        theLayer.contents=[someHelperObject loadStateYesImage];
    }
    else {
        // display the no image
        theLayer.contents=[someHelperObject loadStateNoImage];
    }
}

 

 

    如果你必須重繪圖層的內容,而不是通過加載圖片,那你需要實現drawLayer:inContext:方法。通過委託可以決定哪些內容是需要的並使用CGContextRef來重繪內容。

下面的例子是“指定圖層的幾何”部分內容,它實現了drawLayer:inContext:方法使用lineWidth鍵值來重繪一個路徑(path),返回therLayer。

 

代碼 3  代理方法drawLayer:inContext:的實現示例

- (void)drawLayer:(CALayer *)theLayer
        inContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();

    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );

    CGContextSetLineWidth(theContext,
                          [[theLayer valueForKey:@"lineWidth"] floatValue]);
    CGContextStrokePath(theContext);

    // release the path
    CFRelease(thePath);
}

 

 

1.1.3 通過子類提供圖層的內容

雖然通常情況不需要這樣做,但是你仍可以繼承CALayer直接重載重繪和顯示方法。這個通常發生在你的圖層需要定製行爲而委託又無法滿足需求的時候。

子類可以重載CALayer的顯示方法,設置圖層的內容爲適當的圖片。下面的例子是“變換圖層的幾何”部分的內容,它提供了和“圖層的座標系”例子相同的功能。不同的是子類定義state爲實例的屬性,而不是根據CALayer的鍵-值編碼容器獲取。

 

代碼 4  CALayer display 方法的覆蓋示例

- (void)display
{
    // check the value of the layer's state key
    if (self.state)
    {
        // display the yes image
        self.contents=[someHelperObject loadStateYesImage];
    }
    else {
        // display the no image
        self.contents=[someHelperObject loadStateNoImage];
    }
}

 

 

    CALayer子類可以通過重載drawInContext:繪製圖層的內容到一個圖形上下文。下面的例子是“修改變換的數據結構”的內容,它和“指定圖層的幾何”裏面實現委託的辦法一樣產生相同的圖片內容。唯一的不同的是實現委託裏面的lineWidth和lineColor現在是子類實例的屬性。

Listing 5  覆蓋layer的drawInContext:方法示例

 - (void)drawInContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();

    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );

    CGContextSetLineWidth(theContext,
                          self.lineWidth);
    CGContextSetStrokeColorWithColor(theContext,
                                     self.lineColor);
    CGContextStrokePath(theContext);
    CFRelease(thePath);
}
 

   

繼承CALayer並且實現其中的重繪方法並不意味重繪會自動發生。你必須顯式的促使實例重新緩存其內容,可以通過發送以下任何一個方法setNeedsDisplay或setNeedsDisplayInRect:的消息,亦或者設置圖層的needsDisplaOnBoundsChange屬性爲YES。

 

1.2 修改圖層內容的位置

CALayer的屬性contentsGravity允許你在圖層的邊界內容修改圖層的contents圖片的位置或者伸縮值。默認情況下,內容的圖像完全填充層的邊界,忽視自然的圖像寬高比。

使用contentsGravity位置常量,你可以指定圖片位於圖層任何一個邊界,比如位於圖層的角落,或者圖層邊界的中心。然而當你使用位置常量的時候,contentsCenter屬性會被忽略。表1列舉了位置常量和他們相應的位置。

   

表 1  layer的contentsGravity屬性的定位常量

Position constant

Description

kCAGravityTopLeft

Positions the content image in the top left corner of the layer.

kCAGravityTop

Positions the content image horizontally centered along the top edge of the layer.

kCAGravityTopRight

Positions the content image in the top right corner of the layer.

kCAGravityLeft

Positions the content image vertically centered on the left edge of the layer.

kCAGravityCenter

Positions the content image at the center of the layer.

kCAGravityRight

Positions the content image vertically centered on the right edge of the layer.

kCAGravityBottomLeft

Positions the content image in the bottom left corner of the layer.

kCAGravityBottom

Positions the content image centered along the bottom edge of the layer.

kCAGravityBottomRight

Positions the content image in the top right corner of the layer.

 

“圖層的座標系”標識了所支持的內容位置和他們相應的常量。

圖 1  layer的contentsGravity屬性的定位常量

 

 

    通過設置contentsGravity屬性爲其他一個常量(如表2所示)。圖層的內容圖片可以被向上或者向下拉伸, 僅當使用其他任何一個調整大小的常量的時候,contentsCenter屬性纔會對內容圖片起作用。

 

表 2  Layer的 contentsGravity 屬性的縮放常量

Scaling constant

Description

kCAGravityResize

Resize the content image to completely fill the layer bounds, potentially ignoring the natural aspect of the content. This is the default.

kCAGravityResizeAspect

Resize the content image to scale such that it is displayed as large as possible within the layer bounds, yet still retains its natural aspect.

kCAGravityResizeAspectFill

Resize the content image to scale such that it is displayed filling the layer bounds, yet retaining its natural aspect. This may cause the content to extend outside the layer bounds.

“變換圖層的幾何”演示瞭如何使用調整大小的模式來調整一個正方形圖像的大小讓其適應圖層的方形邊界。

圖 2  Layer的 contentsGravity 屬性的縮放常量

 

 

注意:使用任何常量kCAGravityResize、kCAGravityResizeAspect和kCAGravityResizeAspectFill和表1中的重心位置常量無關。圖層的內容將會填充整個邊界,所以使用這些常量無法改變圖層內容的位置。

發佈了11 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章