/** * Invalidate the whole view. If the view is visible, * {@link #onDraw(android.graphics.Canvas)} will be called at some point in * the future. * <p> * This must be called from a UI thread. To call from a non-UI thread, call * {@link #postInvalidate()}. * 我们先来看这个方法顾名思义:使无效 * 这个方法的作用是使得整个View无效,所以如果这个View还在显示中,该方法的调用会引起View树的重绘, * 常用于内部调用(比如 setVisiblity())或者需要刷新界面的时候, * 需要在主线程(即UI线程)中调用该方法。 */ publicvoidinvalidate() { invalidate(true); } voidinvalidate(boolean invalidateCache) { invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); } voidinvalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { if (mGhostView != null) { mGhostView.invalidate(true); return; }
//这里判断该子View是否可见或者是否处于动画中 if (skipInvalidate()) { return; }
if (invalidateCache) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; }
// Propagate the damage rectangle to the parent view. //把需要重绘的区域传递给父容器 finalAttachInfoai= mAttachInfo; finalViewParentp= mParent; if (p != null && ai != null && l < r && t < b) { finalRectdamage= ai.mTmpInvalRect; damage.set(l, t, r, b); //调用父容器的方法,向上传递事件 p.invalidateChild(this, damage); } ... }
/** * Don't call or override this method. It is used for the implementation of * the view hierarchy. */ publicfinalvoidinvalidateChild(View child, final Rect dirty) {
//设置 parent 等于自身 ViewParentparent=this;
finalAttachInfoattachInfo= mAttachInfo; if (attachInfo != null) { // If the child is drawing an animation, we want to copy this flag onto // ourselves and the parent to make sure the invalidate request goes // through finalbooleandrawAnimation= (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION;
// Check whether the child that requests the invalidate is fully opaque // Views being animated or transformed are not considered opaque because we may // be invalidating their old position and need the parent to paint behind them. MatrixchildMatrix= child.getMatrix(); finalbooleanisOpaque= child.isOpaque() && !drawAnimation && child.getAnimation() == null && childMatrix.isIdentity(); // Mark the child as dirty, using the appropriate flag // Make sure we do not set both flags at the same time intopaqueFlag= isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
// 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) { if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && view.getSolidColor() == 0) { opaqueFlag = PFLAG_DIRTY; } if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) { //对当前View的标记位进行设置 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag; } }
// Add the new dirty rect to the current one localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); // Intersect with the bounds of the window to skip // updates that lie outside of the visible region finalfloatappScale= mAttachInfo.mApplicationScale; finalbooleanintersected= localDirty.intersect(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); if (!intersected) { localDirty.setEmpty(); } if (!mWillDrawSoon && (intersected || mIsAnimating)) { scheduleTraversals(); } returnnull; }
public void postInvalidate() { postInvalidateDelayed(0); }
public void postInvalidateDelayed(long delayMilliseconds) { // We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); } }