前言
自定义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():绘制它的子孩子
网友评论