Draw对应的方法就叫draw()。是在view中提供。谁先加入到布局中谁先画。画的层级绝对不能变。因为draw直接影响着用户的视觉效果。先画的会被后画的覆盖掉。画的时候如果是一个ViewGroup,会先画自己在画子view.所以draw有绘制流程,就在draw()方法中写死了。所以我们不能更改draw()方法。和layout()方法一样,draw()方法也允许我们重写。但是不建议。透过draw()源码,我们可以看到源码中的注释已经告诉我们draw()的流程。

/*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */

第一步先绘制背景(调用drawBackground(canvas);)。

drawBackground就是把一个背景图片,如果设置的是颜色,系统也会把color转化成bitmap。然后大小就和之前测量出来的大小一致。绘制的时候会更改背景图片的bounds,无论背景图片的bounds有多大,它都会按测量出来的大小进行绘制,背景图片就有可能压缩或者拉伸。而背景图片一定会被全部显示出来的。

第二步和第五步是做一些准备,做一些我们现在已经不用的事情。这个可以不用掌握,这种效果我们已经不再用了。是在android 2.x时代有的效果。边缘模糊效果。我们重点来看第3步和第4步。

第三步是绘制view自身。

制自身时的实现都在onDraw()方法中,View的源码中是个空实现,需要子view去继承实现。

第四步是绘制子view。

绘制子view的代码实现方法是在dispatchDraw(canvas);中,View的源码中是个空实现,需要ViewGroup去继承实现。

最后还有第六步,是最后绘制的,滚动条。

在 onDrawForeground(canvas);中,View的源码中有具体逻辑,所有的view都有scrollbar,默认不显示。

这些都不是我们要重点掌握的,我们重点掌握的是dispatchDraw(canvas);方法。这个方法负责绘制子view,同时负责子view的绘制流程、动画效果、滚动视图。里面的逻辑非常复杂。这个方法是在ViewGroup中实现的。也不建议大家去复写。

方法的一开始就判断它本身有没有动画:

if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {

而这个动画指的是补间动画。属性动画不在这里处理。

之后是padding检查:

        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
        if (clipToPadding) {

接下来是绘制子view:

        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) {
                    more |= drawChild(canvas, transientChild, drawingTime);
                }
                transientIndex++;
                if (transientIndex >= transientCount) {
                    transientIndex = -1;
                }
            }

            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
            }
        }
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

到这里就调用了view的 draw(Canvas canvas, ViewGroup parent, long drawingTime) 方法。其中就是先判断view有没有动画:

        final Animation a = getAnimation();

如果有动画就设置偏移量、缩放值等等。

处理完动画,就处理滑动。

        if (!drawingWithRenderNode) {
            computeScroll();
            sx = mScrollX;
            sy = mScrollY;
        }

view对draw部分进行自定义,复写onDraw()方法。

viewGroup是复写dispatchDraw()方法绘制,因为onDraw()方法要求必须有内容。

results matching ""

    No results matching ""