標籤:ui ios 繪圖 資訊 quartz
貓貓分享,必須精品
原創文章,歡迎轉載。轉載請註明:翟乃玉的部落格
地址:http://blog.csdn.net/u013357243?viewmode=contents
首先,前面部落格說過。qurza2d的上下文中有繪圖資訊和繪圖的屬性。
但是他是怎麼繪製到上下午中的呢?
我們畫圖時候一半會用這三個步驟:
(1)擷取上下文
(2)繪圖
(3)渲染
這裡引申出來一個問題,畫兩條線的時候,是怎麼工作呢?
畫兩條相交的線
設定線段的寬度:兩頭為圓形,顏色等。
代碼:
- (void)drawRect:(CGRect)rect{ //擷取上下文 CGContextRef ctx=UIGraphicsGetCurrentContext(); //繪圖 //第一條線 CGContextMoveToPoint(ctx, 30, 130); CGContextAddLineToPoint(ctx, 250, 130); //設定第一條線的狀態 //設定線條的寬度 CGContextSetLineWidth(ctx, 12); //設定線條的顏色 [[UIColor redColor]set]; //設定線條兩端的樣式為圓角 CGContextSetLineCap(ctx,kCGLineCapRound); //對線條進行渲染 CGContextStrokePath(ctx); //第二條線 CGContextMoveToPoint(ctx, 160, 30); CGContextAddLineToPoint(ctx, 160, 200); //渲染 CGContextStrokePath(ctx);}
這時候,我們發現,第二條我們並沒有設定他的顏色和圓角等屬性,但是他還是畫上去了,因為他們共同用了一個上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
畫兩條相交的線,並且讓第二條線段變成最初的樣子
這裡有兩種做法
第一種:清空
在對第二條線進行設定的時候,清空它的狀態
- (void)drawRect:(CGRect)rect{ //擷取上下文 CGContextRef ctx=UIGraphicsGetCurrentContext(); //繪圖 //第一條線 CGContextMoveToPoint(ctx, 30, 130); CGContextAddLineToPoint(ctx, 250, 130); //設定第一條線的狀態 //設定線條的寬度 CGContextSetLineWidth(ctx, 12); //設定線條的顏色 [[UIColor redColor]set]; //設定線條兩端的樣式為圓角 CGContextSetLineCap(ctx,kCGLineCapRound); //對線條進行渲染 CGContextStrokePath(ctx); //第二條線 CGContextMoveToPoint(ctx, 160, 30); CGContextAddLineToPoint(ctx, 160, 200); //清空狀態 CGContextSetLineWidth(ctx, 1); [[UIColor blackColor]set]; CGContextSetLineCap(ctx,kCGLineCapButt); //渲染 CGContextStrokePath(ctx);}
第二種:調換順序
先畫第二條,然後畫第一條。(記得畫完第一個要渲染否則無效。)
- (void)drawRect:(CGRect)rect{ //擷取上下文 CGContextRef ctx=UIGraphicsGetCurrentContext(); //繪圖 //第二條線 CGContextMoveToPoint(ctx, 160, 30); CGContextAddLineToPoint(ctx, 160, 200); //渲染 CGContextStrokePath(ctx); //第一條線 CGContextMoveToPoint(ctx, 30, 130); CGContextAddLineToPoint(ctx, 250, 130); //設定第一條線的狀態 //設定線條的寬度 CGContextSetLineWidth(ctx, 12); //設定線條的顏色 [[UIColor redColor]set]; //設定線條兩端的樣式為圓角 CGContextSetLineCap(ctx,kCGLineCapRound); //對線條進行渲染 CGContextStrokePath(ctx); //渲染 CGContextStrokePath(ctx);}
圖形上下文棧:
上面兩種方法產生的效果差不多,但是還是有略微的區別。
有的情況下,必須要先畫第一條線再畫第二條線,要求在交叉部分,第二條線蓋在第一條線的上面。如果要求是這樣,那麼只能使用第一種做法,但是每次都清空,如果畫的多了,非常麻煩。這裡有個新的東東:圖形上下文棧。
繪圖的完整過程
程式啟動,顯示自訂的view。當程式第一次顯示在我們眼前的時候,程式會調用drawRect:方法,在裡面擷取了圖形上下文(在記憶體中擁有了),然後利用圖形上下文儲存繪圖資訊,可以理解為圖形上下文中有一塊地區用來儲存繪圖資訊,有一塊地區用來儲存繪圖的狀態(線寬,圓角,顏色)。直線不是直接繪製到view上的,可以理解為在圖形上下文中有一塊單獨的地區用來先繪製圖形,當調用渲染方法的時候,再把繪製好的圖形顯示到view上去。
在繪製繪圖區域,會去儲存繪圖狀態區域中尋找對應的狀態資訊(線寬,圓角,顏色),然後在繪圖區域把對第一條直線繪製完成。其實在渲染之前,就已經把直線在繪製繪圖區域畫好了。
這些和本文中的程式碼塊,不具備一一對應關係,只是為了說明繪圖的完整過程。
調用渲染方法的時候,把繪製繪圖區域已經畫好的圖形直接顯示到view上,就是我們看到的樣子了。
畫第二條的時候,如果沒有對繪圖狀態進行重新設定,那麼可以發現畫第一天線的時候使用的繪圖狀態還儲存在圖形上下文中,在第二條線進行渲染之前,會根據第一條線(上一份繪圖狀態)對第二條線進行相應的設定,渲染後把第二條線顯示到螢幕上。
簡單說明圖形上下文棧
在擷取圖形上下文之後,通過 CGContextSaveGState(ctx); 方法,把當前擷取的上下文拷貝一份,儲存一份最純潔的圖形上下文。
在畫第二條線之前,使用CGContextRestoreGState(ctx);方法,還原開始的時候儲存的那份最純潔的圖形上下文。
代碼
- (void)drawRect:(CGRect)rect{ //擷取上下文 CGContextRef ctx=UIGraphicsGetCurrentContext(); //儲存一份最初的圖形上下文 CGContextSaveGState(ctx); //繪圖 //第一條線 CGContextMoveToPoint(ctx, 30, 130); CGContextAddLineToPoint(ctx, 250, 130); //設定第一條線的狀態 //設定線條的寬度 CGContextSetLineWidth(ctx, 12); //設定線條的顏色 [[UIColor redColor]set]; //設定線條兩端的樣式為圓角 CGContextSetLineCap(ctx,kCGLineCapRound); //對線條進行渲染 CGContextStrokePath(ctx); //還原開始的時候儲存的那份最純潔的圖形上下文 CGContextRestoreGState(ctx); //第二條線 CGContextMoveToPoint(ctx, 160, 30); CGContextAddLineToPoint(ctx, 160, 200); //渲染 CGContextStrokePath(ctx);}
這樣就實現了第二條在第一條上面的圖片,看效果:
圖解圖形上下文棧
畫第一條線的時候,會把當前的圖形上下文拷貝一份儲存到圖形上下文棧中。(棧中一個)
畫第二條線的時候,去圖形上下文棧中取出棧頂的繪圖資訊,作為第二條線的狀態資訊,(此時棧中一個被取還剩0個。)第二條線的狀態資訊也是據此進行繪製。
(棧的特點,先進後出)
注意:圖形上下文棧裡面儲存幾次就能取幾次,不能存了一個你取倆,這樣就崩了。
貓貓學IOS(三十一)UI之Quartz2D圖形上下文棧