美文网首页Android UI
自定义View - invalidate()方法源码分析(一)

自定义View - invalidate()方法源码分析(一)

作者: 世道无情 | 来源:发表于2018-01-21 20:57 被阅读90次

    前言

    自定义View - invalidate()方法源码分析(一)
    自定义View - 调用onInvalidate()的时机(二)

    invalidate()方法源码结论:

    分析源码流程:

    如果当前View调用invalidate()方法时,此方法有do while循环,会调用invalidateChildInParent()方法,会一直调到最外层 View的invalidateChildInParent()方法,并且最外层的 View没有 Parent,只要while (parent != null),就会一直去向外层调用View的invalidateChildInParent()方法;
    而里边的 这些parent调用的同样是invalidateChildInParent()方法,只不过这个方法是 ViewGroup中的方法

    一路往上跑,跑到最外层,从当前可见的View,一直到最外层的父View,然后调用最外层View的draw() -- > 再去调用draw()方法中的dispatchDraw() --> 就是这样,再去从最外层一路往下画,就是再去一直往里边View画,最终画到当前调用invalidate()的View的onDraw()方法;

    结论如下:

    invalidate()意思就是:重绘,重新绘制;
    1>:开始是从当前的View,即最里边的View一直会向上边的父View去调用
    2>:然后最外层父View又会一直向里边的子孩子去draw()
    所以只要一调用invalidate()方法,就会牵连着整个Layout布局中的View,如果调用多次,那么肯定会导致页面会卡顿,详情可以参考自定义View - 调用onInvalidate()的时机(二)

    其实invalidate()方法其实只是调用performDraw()方法,并没有调用performMeasure()和performLayout()方法:
    onDraw():绘制自己
    dispatchDraw():绘制它的子孩子

    1. 说明

    上节课我们学习了自定义View--仿QQ运动步数进度效果,里边涉及到invalidate()方法,那么这节课我们就来一起看下系统的invalidate()方法

    2. invalidate()绘制流程

    在ViewGroup源码中有下边这个方法 --> p.invalidateChild(this, damage); Parent父类

    /**
     * Email: 2185134304@qq.com
     * Created by Novate 2018/6/12 8:51
     * Version 1.0
     * Params:
     * Description:    重新绘制子孩子
    */
        @Override
        public final void invalidateChild(View child, final Rect dirty) {
            ViewParent parent = this;
    
           // do...while循环 
           do {
                    View view = null;
                    if (parent instanceof View) {
                        view = (View) parent;
                    }
    
                    if (view != null) {
                    }
    
                    parent = parent.invalidateChildInParent(location, dirty);
                    if (view != null) {
                        // Account for transform on current parent
                        Matrix m = view.getMatrix();
                        if (!m.isIdentity()) {
                            RectF boundingRect = attachInfo.mTmpTransformRect;
                            boundingRect.set(dirty);
                            m.mapRect(boundingRect);
                        }
                    }
                } while (parent != null);
            }
        }
    
    invalidate()绘制流程.png

    由这个重绘子孩子方法可知,下边有个do while 循环:
    如果当前View调用invalidate()方法时,此方法有do while循环,会调用invalidateChildInParent()方法,会一直调到最外层 View的invalidateChildInParent()方法,并且最外层的 View没有 Parent,只要while (parent != null),就会一直去向外层调用View的invalidateChildInParent()方法;
    而里边的 这些parent调用的同样是invalidateChildInParent()方法,只不过这个方法是 ViewGroup中的方法

    一路往上跑,跑到最外层,从当前可见的View,一直到最外层的父View,然后调用最外层View的draw() -- > 再去调用draw()方法中的dispatchDraw() --> 就是这样,再去从最外层一路往下画,就是再去一直往里边View画,最终画到当前调用invalidate()的View的onDraw()方法
    所以由上图可知:
    1>:开始是从当前的View,即最里边的View一直会向上边的父View去调用
    2>:然后最外层父View又会一直向里边的子孩子去draw()
    所以调用invalidate()方法,会牵连着整个Layout布局中的View
    所以:
    当你在当前View调用 invalidate()方法时候 ,它会跑到最外层,去调用最外层的draw()方法,然后再从最外层的View 去draw()它的子孩子,不断的向子孩子去draw(),一直draw()到最里边的View

    3. UI的绘制流程


    [主要是这个方法 performTraversals()非常重要] --> 以下是UI绘制流程的3个重要方法:

    一个布局文件之所以setContentView可以显示出来,其实是做了3个事情:
    1>:performMeasure():调用此方法去测量
    2>:performLayout():调用此方法去摆放位置
    3>:performDraw():调用此方法去绘制
    只需要执行者3个方法,就可以使布局文件显示出来

    而invalidate()方法其实只是调用performDraw()方法

    onDraw():绘制自己
    dispatchDraw():绘制它的子孩子

    相关文章

      网友评论

        本文标题:自定义View - invalidate()方法源码分析(一)

        本文链接:https://www.haomeiwen.com/subject/lcdfaxtx.html