2.2 Custom Drawing(自定義繪制)

2021-09-14 16:00 更新

Custom Drawing

    給contents賦CGImage的值不是唯一的設(shè)置寄宿圖的方法。我們也可以直接用Core Graphics直接繪制寄宿圖。能夠通過繼承UIView并實現(xiàn)-drawRect:方法來自定義繪制。

    -drawRect: 方法沒有默認的實現(xiàn),因為對UIView來說,寄宿圖并不是必須的,它不在意那到底是單調(diào)的顏色還是有一個圖片的實例。如果UIView檢測到-drawRect: 方法被調(diào)用了,它就會為視圖分配一個寄宿圖,這個寄宿圖的像素尺寸等于視圖大小乘以 contentsScale的值。

    如果你不需要寄宿圖,那就不要創(chuàng)建這個方法了,這會造成CPU資源和內(nèi)存的浪費,這也是為什么蘋果建議:如果沒有自定義繪制的任務(wù)就不要在子類中寫一個空的-drawRect:方法。

    當(dāng)視圖在屏幕上出現(xiàn)的時候 -drawRect:方法就會被自動調(diào)用。-drawRect:方法里面的代碼利用Core Graphics去繪制一個寄宿圖,然后內(nèi)容就會被緩存起來直到它需要被更新(通常是因為開發(fā)者調(diào)用了-setNeedsDisplay方法,盡管影響到表現(xiàn)效果的屬性值被更改時,一些視圖類型會被自動重繪,如bounds屬性)。雖然-drawRect:方法是一個UIView方法,事實上都是底層的CALayer安排了重繪工作和保存了因此產(chǎn)生的圖片。

    CALayer有一個可選的delegate屬性,實現(xiàn)了CALayerDelegate協(xié)議,當(dāng)CALayer需要一個內(nèi)容特定的信息時,就會從協(xié)議中請求。CALayerDelegate是一個非正式協(xié)議,其實就是說沒有CALayerDelegate @protocol可以讓你在類里面引用啦。你只需要調(diào)用你想調(diào)用的方法,CALayer會幫你做剩下的。(delegate屬性被聲明為id類型,所有的代理方法都是可選的)。

    當(dāng)需要被重繪時,CALayer會請求它的代理給他一個寄宿圖來顯示。它通過調(diào)用下面這個方法做到的:

(void)displayLayer:(CALayerCALayer *)layer;

    趁著這個機會,如果代理想直接設(shè)置contents屬性的話,它就可以這么做,不然沒有別的方法可以調(diào)用了。如果代理不實現(xiàn)-displayLayer:方法,CALayer就會轉(zhuǎn)而嘗試調(diào)用下面這個方法:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

    在調(diào)用這個方法之前,CALayer創(chuàng)建了一個合適尺寸的空寄宿圖(尺寸由boundscontentsScale決定)和一個Core Graphics的繪制上下文環(huán)境,為繪制寄宿圖做準(zhǔn)備,他作為ctx參數(shù)傳入。

    讓我們來繼續(xù)第一章的項目讓它實現(xiàn)CALayerDelegate并做一些繪圖工作吧(見清單2.5).圖2.12是他的結(jié)果

清單2.5 實現(xiàn)CALayerDelegate

@implementation ViewController
- (void)viewDidLoad
{
  [super viewDidLoad];
  ?
  //create sublayer
  CALayer *blueLayer = [CALayer layer];
  blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
  blueLayer.backgroundColor = [UIColor blueColor].CGColor;

  //set controller as layer delegate
  blueLayer.delegate = self;

  //ensure that layer backing image uses correct scale
  blueLayer.contentsScale = [UIScreen mainScreen].scale; //add layer to our view
  [self.layerView.layer addSublayer:blueLayer];

  //force layer to redraw
  [blueLayer display];
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
  //draw a thick red circle
  CGContextSetLineWidth(ctx, 10.0f);
  CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
  CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
@end

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號