Android UI

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

2018-01-21  本文已影响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():绘制它的子孩子

上一篇 下一篇

猜你喜欢

热点阅读