AndroidView刷新机制
发表时间:2020-10-19
发布人:葵宇科技
浏览次数:48
一:总体解释
在Android的构造体系中,父View负责刷新、构造显示子View;而当子View须要刷新时,则是通知父View来完成。
parent = parent.invalidateChildInParent(location, dirty);
二:代码分析
1).ViewGroup的addView办法,理浇愁数的意义和传递
[img]
invalidate调用父类View的办法
addViewInner办法重要做的工作是
[img]
[img]
view的dispatchAttachedToWindow(AttachInfo info, int visibility)办法
final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() != null;
[img]
1).View的invalidate办法,这是一个大年夜下第向上回溯的过程,每一层的父View都将本身的显示区域与传入的刷新 Rect做交集。
void invalidate(boolean invalidateCache) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
}
if (skipInvalidate()) {
return;
}
if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
(invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
(mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
mPrivateFlags &= ~DRAWN;
mPrivateFlags |= DIRTY;
mPrivateFlags |= INVALIDATED;
mPrivateFlags &= ~DRAWING_CACHE_VALID;
}
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
//noinspection PointlessBooleanExpression,ConstantConditions
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
// with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
}
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
// Don't call invalidate -- we don't want to internally scroll
// our own bounds
p.invalidateChild(this, r);//调用子类的办法完成
if (invalidateCache) {
}
}
}
2)ViewGrop的invalidateChild办法
public final void invalidateChild(View child, final Rect dirty) {
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
final int[] location = attachInfo.mInvalidateChildLocation;
// 须要刷新的子View的地位
4、调用dispatchDraw ()办法绘制子视图(如不雅该View类型不为ViewGroup,即不包含子视图,不须要重载该 办法)值得解释的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用法度榜样一般不须要重写该 办法,但可以重载父类函数实现具体的功能。
location[CHILD_LEFT_INDEX] = child.mLeft;
location[CHILD_TOP_INDEX] = child.mTop;
// ourselves and the parent to make sure the invalidate request goes through
final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
// Check whether the child that requests the invalidate is fully opaque
} else if (parent instanceof ViewRoot) {
// Mark the child as dirty, using the appropriate flag
// Make sure we do not set both flags at the same time
final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
View view = null;
if (parent instanceof View) {
view = (View) parent;
}
if (drawAnimation) {
if (view != null) {
}
}
// 根据父View的地位,偏移刷新区域
// If the parent is dirty opaque or not dirty, mark it dirty with the opaque
// flag coming from the child that initiated the invalidate
if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
}
} while (parent != null);
}
}
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
if ((mPrivateFlags & DRAWN) == DRAWN) {
if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
FLAG_OPTIMIZE_INVALIDATE) {
dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, location[CHILD_TOP_INDEX] - mScrollY);
final int left = mLeft;
final int top = mTop;
// If the child is drawing an animation, we want to copy this flag onto
//计算实际可刷新区域
if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
(mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
location[CHILD_LEFT_INDEX] = left;
location[CHILD_TOP_INDEX] = top;
return mParent;
mLastIsOpaque = isOpaque();
}
} else {
mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX] = mLeft;
location[CHILD_TOP_INDEX] = mTop;
dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
mBottom - location[CHILD_TOP_INDEX]);
return mParent;
}
}
return null;
}
mView.draw()开端绘制,draw()办法实现的功能如下:
这个向上回溯的过程直到ViewRoot那边停止,由ViewRoot对这个最终的刷新区域做刷新
ViewRoot.java
((ViewRoot) parent).mIsAnimating = true;
public void invalidateChild(View child, Rect dirty) {
}
由ViewRoot对象的performTraversals()办法调用draw()办法提议绘制该View树,值得留意的是每次提议画图时,并不会从新绘制每个View树的视图,而只会从新绘制那些“须要重绘”的视图,View类内部变量包含了一个标记位DRAWN,当该视图须要重绘时,就会为该View添加该标记位。
调用流程 :
do {
view.mPrivateFlags |= DRAW_ANIMATION;
1 、绘制该View的背景
2 、为显示渐变框做一些预备操作(见5,大年夜多半情况下,不须要改渐变框)
3、调用onDraw()办法绘制视图本身 (每个View都须要重载该办法,ViewGroup不须要实现该办法)
mPrivateFlags &= ~DRAWING_CACHE_VALID;
4.1 dispatchDraw()办法内部会遍历每个子视图,调用drawChild()去从新回调每个子视图的draw()办法(留意, 这个 处所“须要重绘”的视图才会调用draw()办法)。值得解释的是,ViewGroup类已经为我们重写了dispatch Draw()的功能实现,应用法度榜样一般不须要重写该办法,但可以重载父类函数实现具体的功能。