首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

戏说Android view 工作流程《上》

2012-09-08 
戏说Android view 工作流程《下》遍历View树performTraversals()执行过程view树遍历概述还是回到ViewRoot.ja

戏说Android view 工作流程《下》

遍历View树performTraversals()执行过程

view树遍历概述

还是回到ViewRoot.java,我们直接看performTraversals(),该函数就是android系统View树遍历工作的核心。一眼看去,发现这个函数挺长的,但是逻辑是非常清晰的,其执行过程可简单概括为根据之前所有设置好的状态,判断是否需要计算视图大小(measure)、是否需要重新安置视图的位置(layout),以及是否需要重绘(draw)视图,可以用以下图来表示该流程。

  戏说Android view 工作流程《上》


从上图可以看出,measure过程始于ViewRoot的host.measure(),调的就是view类的measure()函数,该函数然后回调onMeasure。如果host对象是一个ViewGroup实例,一般会重载onMeasure,如果没有的话,则会执行view类中默认的onMeasure。合理的情况是编程人员重载onMeasure并逐一对里面的子view进行measure。我们可以看一下view的measure方法:

   



眼尖的同学应该发现了,上面这张图比前面的measure和layout多了一步:draw()。在performTraversals()函数中调用的是viewRoot的draw()函数,在该函数中进行一系列的前端处理后,再调用host.draw()。

一般情况下,View对象不应该重载draw()函数,因此,host.draw()就是view.draw()。该函数内部过程也就是View系统绘制过程的核心过程,该函数中会依次绘制前面所说哦四种元素,其中绘制视图本身的具体实现就是回调onDraw()函数,应用程序一般也会重载onDraw()函数以绘制所设计的View的真正界面内容。

Google源码的注释太nice了,我加任何说辞都显得多余,就不画蛇添足了:

 protected void dispatchDraw(Canvas canvas) {        final int count = mChildrenCount;        final View[] children = mChildren;        int flags = mGroupFlags;//1 判断mGroupFlags是否设有FLAG_RUN_ANIMATION标识并且不为0.该layout动画指的是加载或移除子视图时候呈现的动画.        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;            final boolean buildCache = !isHardwareAccelerated();//硬件加速,4.0加入.            for (int i = 0; i < count; i++) {                final View child = children[i];                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {                    final LayoutParams params = child.getLayoutParams();                    attachLayoutAnimationParameters(child, params, i, count);                    bindLayoutAnimation(child);            }        }//2 处理padding属性,如果该viewGroup有设置.        int saveCount = 0;        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;        if (clipToPadding) {            saveCount = canvas.save();            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,                    mScrollX + mRight - mLeft - mPaddingRight,                    mScrollY + mBottom - mTop - mPaddingBottom);        }//3 开始绘制子视图动画之前先清除flag.        // We will draw our child's animation, let's reset the flag        mPrivateFlags &= ~DRAW_ANIMATION;        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;        boolean more = false;        final long drawingTime = getDrawingTime();//4 使用佛如循环,使viewGroup的子视图逐个调用drawChild函数.        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {            for (int i = 0; i < count; i++) {                final View child = children[i];                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {                    more |= drawChild(canvas, child, drawingTime);                }            }        } else {            for (int i = 0; i < count; i++) {                final View child = children[getChildDrawingOrder(count, i)];                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {                    more |= drawChild(canvas, child, drawingTime);                }            }        }//5 Draw any disappearing views that have animations        if (mDisappearingChildren != null) {            final ArrayList<View> disappearingChildren = mDisappearingChildren;            final int disappearingCount = disappearingChildren.size() - 1;            // Go backwards -- we may delete as animations finish            for (int i = disappearingCount; i >= 0; i--) {                final View child = disappearingChildren.get(i);                more |= drawChild(canvas, child, drawingTime);            }        }        if (clipToPadding) {            canvas.restoreToCount(saveCount);        }// mGroupFlags might have been updated by drawChild()        flags = mGroupFlags;        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {            invalidate(true);        }    }

整个view的工作流程那是相当复杂的,这需要静下心来,加以时日细细揣摩才能略有体会,本人写有小Demo一个,就当抛砖引玉:ClickMe!


  

热点排行