invalidate内部思想
invalidate的调用流图
View.invalidateInternal
打上DIRTY标记
为后面Draw做准备
mPrivateFlags |= PFLAG_DIRTY;
调用父组件的invalidateChild
并将自身相对位置left,top,right,bottom通知给父组件
ViewGroup.invalidateChild
循环执行父组件的invalidateChildInParent,直到执行到ViewRootImpl完后会返回null,也就到头了。
ViewGroup.invalidateChildInParent
需要重绘的区域由两个数据来定义的:
- location数组:为自身左边,上边距离父组件的距离。确立了在坐标系的相对位置
- dirty:一个包含自身宽高的矩形面积。确立了需要重绘的面积大小
二者告知了在屏幕的具体哪个区域是需要重绘的。
ViewRootImpl.invalidateChildInParent
ViewRootImpl.invalidateRectOnScreen
加入重绘区域合集
localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
本次invalidate的dirty区域同之前的dirty区域合并
final boolean intersected = localDirty.intersect(0, 0,
(int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
if (!intersected) {
localDirty.setEmpty();
}
判断要重绘的区域是不是在屏幕内,也就是判断dirty和屏幕区域是否有交叉,屏幕外的就不用去绘制了。
scheduleTraversals();
开始遍历绘制
invalidate()使用场景
一般引起invalidate()操作的函数如下:
1、直接调用invalidate()方法,请求重新draw(),但只会绘制调用者本身。
2、setSelection()方法 :请求重新draw(),但只会绘制调用者本身。
3、setVisibility()方法 : 当View可视状态在INVISIBLE转换VISIBLE时,会间接调用invalidate()方法,继而绘制该View。
4 、setEnabled()方法 : 请求重新draw(),但不会重新绘制任何视图包括该调用者本身。