View中:
publicvoiddraw(Canvas canvas) {
/*
1. Draw the background ? 繪制背景
2. If necessary, save the canvas' layers to prepare for fading ?如有必要细疚,顏色漸變淡之前保存畫布層(即鎖定原有的畫布內(nèi)容)
3. Draw view's content ?繪制view的內(nèi)容
4. Draw children ? ?繪制子view
5. If necessary, draw the fading edges and restore layers ? 如有必要蔗彤,繪制顏色漸變淡的邊框,并恢復(fù)畫布(即畫布改變的內(nèi)容附加到原有內(nèi)容上)
6. Draw decorations (scrollbars for instance) ? 繪制裝飾疯兼,比如滾動(dòng)條
*/
...
if(!dirtyOpaque) {
drawBackground(canvas); //背景繪制
}
// skip step 2 & 5 if possible (common case) 通常情況跳過第2和第5步
...
if(!dirtyOpaque)onDraw(canvas);//調(diào)用onDraw
dispatchDraw(canvas);//繪制子view
onDrawScrollBars(canvas); //繪制滾動(dòng)條
...
}
protectedvoiddispatchDraw(Canvas canvas) { //空實(shí)現(xiàn) }
protectedvoidonDraw(Canvas canvas) { //空實(shí)現(xiàn) }
ViewGroup中:
protectedvoiddispatchDraw(Canvas canvas) {
...
drawChild(...); //繪制子view
...
}
protectedbooleandrawChild(Canvas canvas, View child,longdrawingTime) {
returnchild.draw(canvas,this, drawingTime);
}
說明:
1. 自定義一個(gè)view時(shí)然遏,重寫onDraw。
調(diào)用view.invalidate(),會(huì)觸發(fā)onDraw和computeScroll()吧彪。前提是該view被附加在當(dāng)前窗口上
view.postInvalidate(); //是在非UI線程上調(diào)用的
2. ?自定義一個(gè)ViewGroup待侵,重寫onDraw。
onDraw可能不會(huì)被調(diào)用姨裸,原因是需要先設(shè)置一個(gè)背景(顏色或圖)秧倾。
表示這個(gè)group有東西需要繪制了,才會(huì)觸發(fā)draw傀缩,之后是onDraw那先。
因此,一般直接重寫dispatchDraw來繪制viewGroup
3.自定義一個(gè)ViewGroup
dispatchDraw會(huì)調(diào)用drawChild赡艰。
繪制VIew本身的內(nèi)容售淡,通過調(diào)用View.onDraw(canvas)函數(shù)實(shí)現(xiàn)
繪制自己的孩子通過dispatchDraw(canvas)實(shí)現(xiàn)
View組件的繪制會(huì)調(diào)用draw(Canvas canvas)方法,draw過程中主要是先畫Drawable背景慷垮,對(duì) drawable調(diào)用setBounds()然后是draw(Canvas c)方法.有點(diǎn)注意的是背景drawable的實(shí)際大小會(huì)影響view組件的大小勋又,drawable的實(shí)際大小通過getIntrinsicWidth()和getIntrinsicHeight()獲取,當(dāng)背景比較大時(shí)view組件大小等于背景drawable的大小
畫完背景后换帜,draw過程會(huì)調(diào)用onDraw(Canvas canvas)方法楔壤,然后就是dispatchDraw(Canvas canvas)方法, dispatchDraw()主要是分發(fā)給子組件進(jìn)行繪制,我們通常定制組件的時(shí)候重寫的是onDraw()方法惯驼。值得注意的是ViewGroup容器組件的繪制蹲嚣,當(dāng)它沒有背景時(shí)直接調(diào)用的是dispatchDraw()方法, 而繞過了draw()方法递瑰,當(dāng)它有背景的時(shí)候就調(diào)用draw()方法,而draw()方法里包含了dispatchDraw()方法的調(diào)用隙畜。因此要在ViewGroup上繪制東西的時(shí)候往往重寫的是dispatchDraw()方法而不是onDraw()方法抖部,或者自定制一個(gè)Drawable,重寫它的draw(Canvas c)和 getIntrinsicWidth(),?getIntrinsicHeight()方法议惰,然后設(shè)為背景慎颗。
draw()繪圖過程
由ViewRoot對(duì)象的performTraversals()方法調(diào)用draw()方法發(fā)起繪制該View樹,值得注意的是每次發(fā)起繪圖時(shí)言询,并不會(huì)重新繪制每個(gè)View樹的視圖俯萎,而只會(huì)重新繪制那些“需要重繪”的視圖,View類內(nèi)部變量包含了一個(gè)標(biāo)志位DRAWN运杭,當(dāng)該視圖需要重繪時(shí)夫啊,就會(huì)為該View添加該標(biāo)志位。
調(diào)用流程 :
mView.draw()開始繪制辆憔,draw()方法實(shí)現(xiàn)的功能如下:
1 撇眯、繪制該View的背景
2 、為顯示漸變框做一些準(zhǔn)備操作(見5虱咧,大多數(shù)情況下熊榛,不需要改漸變框)
3、調(diào)用onDraw()方法繪制視圖本身 (每個(gè)View都需要重載該方法腕巡,ViewGroup不需要實(shí)現(xiàn)該方法)
4玄坦、調(diào)用dispatchDraw ()方法繪制子視圖(如果該View類型不為ViewGroup,即不包含子視圖逸雹,不需要重載該方法)
值得說明的是营搅,ViewGroup類已經(jīng)為我們重寫了dispatchDraw ()的功能實(shí)現(xiàn),應(yīng)用程序一般不需要重寫該方法梆砸,但可以重載父類函數(shù)實(shí)現(xiàn)具體的功能转质。
4.1 dispatchDraw()方法內(nèi)部會(huì)遍歷每個(gè)子視圖,調(diào)用drawChild()去重新回調(diào)每個(gè)子視圖的draw()方法(注意帖世,這個(gè)地方“需要重繪”的視圖才會(huì)調(diào)用draw()方法)休蟹。值得說明的是,ViewGroup類已經(jīng)為我們重寫了dispatchDraw()的功能實(shí)現(xiàn)日矫,應(yīng)用程序一般不需要重寫該方法赂弓,但可以重載父類函數(shù)實(shí)現(xiàn)具體的功能。
5哪轿、繪制滾動(dòng)條
于是盈魁,整個(gè)調(diào)用鏈就這樣遞歸下去了。