View绘制流程(六) - invalidate()

1. invalidate


invalidate:重新绘制的意思

2. invalidate()源码


   // 这个其实就是 invalidate() 重绘 
   void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
            boolean fullInvalidate) {

        // 首先调用 skipInvalidate判断,当前 view 是否需要重新绘制
        if (skipInvalidate()) {
            return;
        }
        // 然后调用 ViewGroup的 invalidateChild
        p.invalidateChild(this, damage);
        }
    }

    // 判断 当前 view 是否需要重绘,判断逻辑是:如果当前view不可见并且没有动画,就不用重绘
    private boolean skipInvalidate() {
        return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null &&
                (!(mParent instanceof ViewGroup) ||
                        !((ViewGroup) mParent).isViewTransitioning(this));
    }

ViewGroup的 invalidateChild()方法:

public final void invalidateChild(View child, final Rect dirty) {
        ViewParent parent = this;

            // 这里是一个 do...while循环,
            do {
                View view = null;
                if (parent instanceof View) {
                    // 这里不断的获取当前 view 的 父view布局 ,然后最终就会 获取到最外层的 ViewGroup
                    view = (View) parent;
                }
                // 然后调用 ViewGroup的 invalidateChildInParent ,作用是计算要绘制的矩形区域
                // 当循环到最外层后,就调用  ViewParent.invalidateChildInParent
                parent = parent.invalidateChildInParent(location, dirty);
                }
            } while (parent != null);
        }
    }
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
    checkThread();
    scheduleTraversals();
}

分析上边源码:
1>:在 invalidate 方法中:首先调用 skipInvalidate,作用是 判断当前 view 是否需要重新绘制,判断逻辑是:
如果当前 view 不可见并且没有动画,就不用重绘;
如果需要重绘:调用 ViewGroup.invalidateChild;

2>:在 ViewGroup的 invalidateChild 中:
有一个 do...while循环,在do中不断的获取当前view的父view (只是当前的view的父布局,并不是最外层ViewGroup),然后调用 该view的父布局的invalidateChildInParent,一直调用到最外层的 ViewGroup(这个才是最外层的ViewGroup)的 invalidateChildInParent;

然后中间会经过一系列调用,调用到 performTraversals(),然后调用 performDraw;

当调用到最外层后,就开始从最外层向最里层绘制, 从最外层开始调用view的 draw绘制,然后一直调用到最里层 view 的 draw 进行绘制;

这个就是 invalidate() 绘制流程

3. 总结


1>:invalidate绘制流程就是:从当前view 不断的获取它的 父布局ViewGroup,一直获取到最外层的ViewGroup,然后从最外层的 ViewGroup 开始调用 draw绘制,一直绘制到最里层当前 view;
2>:invalidate只是调用performDraw,没有调用 performMeasure、performLayout,如果需要执行完整的绘制流程,可以调用 requestLayout
3>:流程图如下:

图片.png

4. invalidate调用时机


代码中只要调用 setText()、setVisibility()、setEnable()、setFocused()等方法,里边都会调用 invalidate()方法,表示 强制让view 重绘;

只要一调用 invalidate,不断获取当前view 的 父布局,然后调用父布局的 invalidateChildInParent,一直调用到最外层的 ViewGroup的 invalidateChildInParent,然后再从最外层开始一直向最里层的view调用 draw绘制,每调用一次invalidate方法都会牵连整个layout布局,如果多次调用,就会影响页面卡顿;

你可能感兴趣的:(View绘制流程(六) - invalidate())