View框架之draw()流程
来源:互联网 发布:geo数据库教程 编辑:程序博客网 时间:2024/05/18 01:22
在前两篇我们分别描述了View的测量和布局,今天我们就针对绘制的最后一步draw()进行分析。
-
在开始我们还是先贴张时序图,然后针对图中的方法进行梳理
-
draw()流程相对于测量和布局要简单很多,我们还是从ViewRootimpl中的performDraw()开始分析
private void performDraw() { /** 省略部分代码 draw(fullRedrawNeeded); /** 省略部分代码} private void draw(boolean fullRedrawNeeded) {/**省略部分代码 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) { return; }}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer. final Canvas canvas; try { //获取需要重绘的位置 final int left = dirty.left; final int top = dirty.top; final int right = dirty.right; final int bottom = dirty.bottom; //锁定,获取对应的canvas canvas = mSurface.lockCanvas(dirty); canvas.setDensity(mDensity); } try { if (DEBUG_ORIENTATION || DEBUG_DRAW) { Log.v(TAG, "Surface " + surface + " drawing to bitmap w=" + canvas.getWidth() + ", h=" + canvas.getHeight()); //canvas.drawARGB(255, 255, 0, 0); } /**省略部分代码 //调用DecorView的draw方法 mView.draw(canvas); } }}
接着就执行到了我们DecorVeiw的draw()方法,draw()方法,基本上我们绘制的主要操作都在这里面
下面方法主要做了这几件事情:
1.绘制背景 2.绘制View本身 3.如果本身是ViewGroup的时候,绘制子View 4.绘制装饰部分,滚动条等等...
@CallSuper
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
// Step 1, draw the background, if needed int saveCount; if (!dirtyOpaque) { //绘制背景,如果背景不为透明的情况下 drawBackground(canvas); } // skip step 2 & 5 if possible (common case) 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 //绘制View的主要内容,一般子类需要重写此方法 if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children //绘制子View,就是调用子View的draw()方法 dispatchDraw(canvas); // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // Step 6, draw decorations (foreground, scrollbars) //绘制装饰部分,例如滚动条等 onDrawForeground(canvas); // we're done... return; }
dispatchDraw()本身在View中是一个空实现,真正的实现在ViewGroup中,该方法主要起的作用是循环遍历每一个子View,并执行drawChild();
@Override
protected void dispatchDraw(Canvas canvas) {
boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
final int childrenCount = mChildrenCount;
int clipSaveCount = 0; final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; if (clipToPadding) { clipSaveCount = canvas.save(); canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, mScrollX + mRight - mLeft - mPaddingRight, mScrollY + mBottom - mTop - mPaddingBottom); } /** 省略部分代码 for (int i = 0; i < childrenCount; i++) { while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) { final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { /////////调用drawChild more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { transientIndex = -1; } } }}-
接着再看一下drawChild()的代码
protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this, drawingTime);}--
这个draw()也是view里面的方法,被drawChild()方法调用,主要判断是否有绘制缓存,如果有,直接使用缓存,如果没有,重复调用上面的draw()方法
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { // Fast path for layouts with no backgrounds if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); } else { draw(canvas); } } }
–
总结几点:
1.onDraw()必须在View需要我们自己去实现,绘制内容
2.dispathDraw()在ViewGroup已经实现好,默认会调用子View的draw()方法
3.view的绘制的顺序就是我们给一个ViewGroup添加子View的顺序
-
差不多draw()的主要内容就这么多了,到目前为止,view的三大流程已经讲述完毕,谢谢大家的阅读!
- View框架之draw()流程
- Android View框架总结(六)View布局流程之Draw过程
- Android View框架总结(六)View布局流程之Draw过程
- view绘制流程之layout和draw
- Android自定义view之measure、layout、draw三大流程
- View的绘制流程分析之四 -- draw
- View的Draw方法流程
- View框架之measure()流程
- View框架之layout()流程
- View显示流程-View draw的准备工作
- android view的讲解 之 view的工作流程(measure,layout,draw)(二)
- View绘制之draw过程
- 自定义view之draw篇
- android View draw方法传递流程
- Android View 绘制流程(Draw) 完全解析
- Android View 绘制流程(Draw) 完全解析
- View 和ViewGroup 的draw流程
- Android应用层View绘制流程之measure,layout,draw三步曲
- vpn
- Nginx 上传不了,只能上传1M内文件
- Ubuntu下Nexus开机启动
- javascript 获取URL参数(一)
- MySQL InnoDB体系架构之内存
- View框架之draw()流程
- 类别和类扩展
- hibernate中 openSession和getCurrentSession的区别
- word分章节添加页眉
- mpls vpn
- 侧滑菜单的实现总结
- EasyUI DataGrid中loadFilter 属性的用法
- php create_function()产生的漏洞
- Moncler Jakke Herre course she is the