当前位置:   article > 正文

android监听ondraw方法,Android视图绘制流程之onDraw()

监听状态怎么画流程图

measure和layout的过程都结束后,接下来就进入到draw的过程了。

同样,根据名字你就能够判断出,在这里才真正地开始对视图进行绘制。

ViewRoot中的代码会继续执行并创建出一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工作。

draw()方法内部的绘制过程总共可以分为六步,其中第二步和第五步在一般情况下很少用到,因此这里我们只分析简化后的绘制过程。代码如下所示:

public void draw(Canvas canvas) {

if (ViewDebug.TRACE_HIERARCHY) {

ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);

}

final int privateFlags = mPrivateFlags;

final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&

(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);

mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;

// Step 1, draw the background, if needed

int saveCount;

if (!dirtyOpaque) {

final Drawable background = mBGDrawable;

if (background != null) {

final int scrollX = mScrollX;

final int scrollY = mScrollY;

if (mBackgroundSizeChanged) {

background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);

mBackgroundSizeChanged = false;

}

if ((scrollX | scrollY) == 0) {

background.draw(canvas);

} else {

canvas.translate(scrollX, scrollY);

background.draw(canvas);

canvas.translate(-scrollX, -scrollY);

}

}

}

final int viewFlags = mViewFlags;

boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;

boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;

if (!verticalEdges && !horizontalEdges) {

// Step 3, draw the content

if (!dirtyOpaque) onDraw(canvas);

// Step 4, draw the children

dispatchDraw(canvas);

// Step 6, draw decorations (scrollbars)

onDrawScrollBars(canvas);

// we're done...

return;

}

}

可以看到,第一步的作用是对视图的背景进行绘制。

这里会先得到一个mBGDrawable对象

然后根据layout过程确定的视图位置来设置背景的绘制区域

之后再调用Drawable的draw()方法来完成背景的绘制工作。

那么这个mBGDrawable对象是从哪里来的呢?其实就是在XML中通过android:background属性设置的图片或颜色。

当然你也可以在代码中通过setBackgroundColor()、setBackgroundResource()等方法进行赋值。

接下来,第三步的作用是对视图的内容进行绘制。

这里去调用了一下onDraw()方法

那么onDraw()方法里又写了什么代码呢?进去一看你会发现,原来又是个空方法啊。其实也可以理解,因为每个视图的内容部分肯定都是各不相同的,这部分的功能交给子类来去实现也是理所当然的。

接下来第四步的作用是对当前视图的所有子视图进行绘制。

(但如果当前的视图没有子视图,那么也就不需要进行绘制了。)

因此你会发现View中的dispatchDraw()方法又是一个空方法,而ViewGroup的dispatchDraw()方法中就会有具体的绘制代码。

以上都执行完后就会进入到第六步,也是最后一步,这一步的作用是对视图的滚动条进行绘制。

那么你可能会奇怪,当前的视图又不一定是ListView或者ScrollView,为什么要绘制滚动条呢?其实不管是Button也好,TextView也好,任何一个视图都是有滚动条的,只是一般情况下我们都没有让它显示出来而已。绘制滚动条的代码逻辑也比较复杂,这里就不再贴出来了,因为我们的重点是第三步过程。

通过以上流程分析,相信大家已经知道,View是不会帮我们绘制内容部分的,因此需要每个视图根据想要展示的内容来自行绘制。如果你去观察TextView、ImageView等类的源码,你会发现它们都有重写onDraw()这个方法,并且在里面执行了相当不少的绘制逻辑。绘制的方式主要是借助Canvas这个类,它会作为参数传入到onDraw()方法中,供给每个视图使用。Canvas这个类的用法非常丰富,基本可以把它当成一块画布,在上面绘制任意的东西,那么我们就来尝试一下吧。

这里简单起见,我只是创建一个非常简单的视图,并且用Canvas随便绘制了一点东西,代码如下所示:

public class MyView extends View {

private Paint mPaint;

public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

}

@Override

protected void onDraw(Canvas canvas) {

mPaint.setColor(Color.YELLOW);

canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);

mPaint.setColor(Color.BLUE);

mPaint.setTextSize(20);

String text = "Hello View";

canvas.drawText(text, 0, getHeight() / 2, mPaint);

}

}

可以看到,我们创建了一个自定义的MyView继承自View,并在MyView的构造函数中创建了一个Paint对象。Paint就像是一个画笔一样,配合着Canvas就可以进行绘制了。

这里我们的绘制逻辑比较简单,在onDraw()方法中先是把画笔设置成黄色,然后调用Canvas的drawRect()方法绘制一个矩形。然后在把画笔设置成蓝色,并调整了一下文字的大小,然后调用drawText()方法绘制了一段文字。

就这么简单,一个自定义的视图就已经写好了,现在可以在XML中加入这个视图,如下所示:

android:layout_width="match_parent"

android:layout_height="match_parent" >

android:layout_width="200dp"

android:layout_height="100dp" />

将MyView的宽度设置成200dp,高度设置成100dp,然后运行一下程序,结果如下图所示:

f0f44cd58711

Screenshot_2019-05-09-09-54-04-016_com.example.di.png

图中显示的内容也正是MyView这个视图的内容部分了。由于我们没给MyView设置背景,因此这里看不出来View自动绘制的背景效果。

当然了Canvas的用法还有很多很多,这里我不可能把Canvas的所有用法都列举出来,剩下的就要靠大家自行去研究和学习了。

到此为止,我们把视图绘制流程的第三阶段也分析完了。整个视图的绘制过程就全部结束了,你现在是不是对View的理解更加深刻了呢?

Home:返回首页

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/673364
推荐阅读
相关标签
  

闽ICP备14008679号