ndroid draw、onDraw、dispatchDraw、invalidate、postInvalidate一些简要说明

View中:

publicvoiddraw(Canvas canvas) {

/*

1. Draw the background   绘制背景

2. If necessary, save the canvas' layers to prepare for fading  如有必要,颜色渐变淡之前保存画布层(即锁定原有的画布内容)

3. Draw view's content  绘制view的内容

4. Draw children    绘制子view

5. If necessary, draw the fading edges and restore layers   如有必要,绘制颜色渐变淡的边框,并恢复画布(即画布改变的内容附加到原有内容上)

6. Draw decorations (scrollbars for instance)   绘制装饰,比如滚动条

*/

...

if(!dirtyOpaque) {

drawBackground(canvas); //背景绘制

}

// skip step 2 & 5 if possible (common case) 通常情况跳过第2和第5步

...

if(!dirtyOpaque)onDraw(canvas);//调用onDraw

dispatchDraw(canvas);//绘制子view

onDrawScrollBars(canvas); //绘制滚动条

...

}

protectedvoiddispatchDraw(Canvas canvas) { //空实现 }

protectedvoidonDraw(Canvas canvas) { //空实现 }

ViewGroup中:

protectedvoiddispatchDraw(Canvas canvas) {

...

drawChild(...); //绘制子view

...

}

protectedbooleandrawChild(Canvas canvas, View child,longdrawingTime) {

returnchild.draw(canvas,this, drawingTime);

}

说明:

1. 自定义一个view时,重写onDraw。

调用view.invalidate(),会触发onDraw和computeScroll()。前提是该view被附加在当前窗口上

view.postInvalidate(); //是在非UI线程上调用的

2.  自定义一个ViewGroup,重写onDraw。

onDraw可能不会被调用,原因是需要先设置一个背景(颜色或图)。

表示这个group有东西需要绘制了,才会触发draw,之后是onDraw。

因此,一般直接重写dispatchDraw来绘制viewGroup

3.自定义一个ViewGroup

dispatchDraw会调用drawChild。


绘制VIew本身的内容,通过调用View.onDraw(canvas)函数实现

绘制自己的孩子通过dispatchDraw(canvas)实现

View组件的绘制会调用draw(Canvas canvas)方法,draw过程中主要是先画Drawable背景,对 drawable调用setBounds()然后是draw(Canvas c)方法.有点注意的是背景drawable的实际大小会影响view组件的大小,drawable的实际大小通过getIntrinsicWidth()和getIntrinsicHeight()获取,当背景比较大时view组件大小等于背景drawable的大小

画完背景后,draw过程会调用onDraw(Canvas canvas)方法,然后就是dispatchDraw(Canvas canvas)方法, dispatchDraw()主要是分发给子组件进行绘制,我们通常定制组件的时候重写的是onDraw()方法。值得注意的是ViewGroup容器组件的绘制,当它没有背景时直接调用的是dispatchDraw()方法, 而绕过了draw()方法,当它有背景的时候就调用draw()方法,而draw()方法里包含了dispatchDraw()方法的调用。因此要在ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法,或者自定制一个Drawable,重写它的draw(Canvas c)和 getIntrinsicWidth(), getIntrinsicHeight()方法,然后设为背景。



draw()绘图过程

由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。

调用流程 :

mView.draw()开始绘制,draw()方法实现的功能如下:

1 、绘制该View的背景

2 、为显示渐变框做一些准备操作(见5,大多数情况下,不需要改渐变框)

3、调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)

4、调用dispatchDraw ()方法绘制子视图(如果该View类型不为ViewGroup,即不包含子视图,不需要重载该方法)

值得说明的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。

4.1 dispatchDraw()方法内部会遍历每个子视图,调用drawChild()去重新回调每个子视图的draw()方法(注意,这个地方“需要重绘”的视图才会调用draw()方法)。值得说明的是,ViewGroup类已经为我们重写了dispatchDraw()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。

5、绘制滚动条

于是,整个调用链就这样递归下去了。

你可能感兴趣的:(ndroid draw、onDraw、dispatchDraw、invalidate、postInvalidate一些简要说明)