原文地址:http://superman474.blog.163.com/blog/static/120661462011857559881/
提供layer內容
當我們使用cocoa view的子類時,我們要實現drawRect:方法去顯示任何東西。然而CALayer實例經常直接使用,不需子類。因爲CALayer是一個key-value coding兼容的容器類,所以我們可以在任何情況下存儲任意值,去子類化一個CALayer通常是可以避免的。
1.提供CALayer內容
可以用下面方式之一去指定一個CALayer實例的內容:
A明確的用一個包含content image的CGImageRef去設置一個layer實例的contents屬性。
B指定一個代理去提供或者繪畫(draw)content。
C子類一個CALayer,然後重寫它的display方法。
(1)設置contents屬性
一個layer的content image可以被指定通過contents屬性(CGImageRef),這可以在layer被創建的時候或者其他任何時候指定。
下面代碼具體設置一個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; |
(2)使用代理去提供內容
我們可以創建一個代理類去實現方法displayLayer: 或者 drawLayer:inContext:去設置layer content image。實現一個代理方法去繪製內容不會自動引起layer用實現的方法去繪製。相反的,我們要明確的告訴layer實例去re-cache內容,通過發送消息setNeedsDisplay 或者setNeedsDisplayInRect:都可以,或者設置屬性needsDisplayOnBoundsChange 爲YES。
實現方法displayLayer:的代理可以確定對於指定的layer應該去顯示哪一個image,然後設置layer的contents屬性。下面是一個代理實現了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]; |
} |
} |
如果我們必須draw一個layer的內容而不是從一個image加載,我們要去實現代理方法
drawLayer:inContext:
。此代理傳遞的參數包括一個請求content的layer和一個CGContextRef去會滑content。
下面就是一個代理實現了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); |
} |
(3)通過實現子類去提供CALayer的content
儘管沒有必要,但是我們yield可以繼承一個CALayer去直接的覆蓋drawing和display方法。當layer需要自定義行爲但是代理不能提供的時候我們用此方法。
一個CALayer的子類可以重寫display方法,並設置恰當的image給layer的content。如下:
- (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:方法去draw layer content 在一個graphics context。
- (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,實現drawing 方法不會自動的去調用drawing。必須明確的去引導實例去re-cache content。通過發送消息setNeedsDisplay或者setNeedsDisplayInRect:都可以,或者設置屬性needsDisplayOnBoundsChange爲YES。
2.positioning layer的content。
CALayer提供一個屬性contentsGravity允許我們去position and scale layer的contents image。缺省情況下,content image填充整個layer bounds。忽視自然的圖像縱橫比。
使用contentsGravity positioning常量去具體image的位置,如下圖:
當使用positioning 常量時,contentsCenter屬性將不在使用。
contentsGravity屬性可以被設置爲下面三種來控制其sacle。設置成下列三種時,上面的9種就失效。