/**     * Invalidate the whole view. If the view is visible,     * {@link #onDraw(android.graphics.Canvas)} will be called at some point in     * the future. This must be called from a UI thread. To call from a non-UI thread,     * call {@link #postInvalidate()}.     */    public void invalidate() {        invalidate(true);    }

view中的invalidate方法会调用invalidate(true);

/**     * This is where the invalidate() work actually happens. A full invalidate()     * causes the drawing cache to be invalidated, but this function can be called with     * invalidateCache set to false to skip that invalidation step for cases that do not     * need it (for example, a component that remains at the same dimensions with the same     * content).     *     * @param invalidateCache Whether the drawing cache for this view should be invalidated as     * well. This is usually true for a full invalidate, but may be set to false if the     * View's contents or dimensions have not changed.     */    void invalidate(boolean invalidateCache) {        if (skipInvalidate()) {            return;        }        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||                (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {            mLastIsOpaque = isOpaque();            mPrivateFlags &= ~PFLAG_DRAWN;            mPrivateFlags |= PFLAG_DIRTY;            if (invalidateCache) {                mPrivateFlags |= PFLAG_INVALIDATED;                mPrivateFlags &= ~PFLAG_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);            }        }    }

最终都会执行mParent的invalidateChild(this, r);如果开启硬件加速的话,r=null,即重绘整个View,r代表需要绘制的区域,r.set方法的调用设置了需要绘制区域的长和高。

下面看一下invalidateChild()方法

/**     * Don't call or override this method. It is used for the implementation of     * the view hierarchy.     */    public final void invalidateChild(View child, final Rect dirty) {        ViewParent parent = this;        final AttachInfo attachInfo = 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            final boolean drawAnimation = (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.            Matrix childMatrix = child.getMatrix();            final boolean isOpaque = 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            int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;            if (child.mLayerType != LAYER_TYPE_NONE) {                mPrivateFlags |= PFLAG_INVALIDATED;                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;                child.mLocalDirtyRect.union(dirty);            }            final int[] location = attachInfo.mInvalidateChildLocation;            location[CHILD_LEFT_INDEX] = child.mLeft;            location[CHILD_TOP_INDEX] = child.mTop;            if (!childMatrix.isIdentity() ||                    (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {                RectF boundingRect = attachInfo.mTmpTransformRect;                boundingRect.set(dirty);                Matrix transformMatrix;                if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {                    Transformation t = attachInfo.mTmpTransformation;                    boolean transformed = getChildStaticTransformation(child, t);                    if (transformed) {                        transformMatrix = attachInfo.mTmpMatrix;                        transformMatrix.set(t.getMatrix());                        if (!childMatrix.isIdentity()) {                            transformMatrix.preConcat(childMatrix);                        }                    } else {                        transformMatrix = childMatrix;                    }                } else {                    transformMatrix = childMatrix;                }                transformMatrix.mapRect(boundingRect);                dirty.set((int) (boundingRect.left - 0.5f),                        (int) (boundingRect.top - 0.5f),                        (int) (boundingRect.right + 0.5f),                        (int) (boundingRect.bottom + 0.5f));            }            do {                View view = null;                if (parent instanceof View) {                    view = (View) parent;                }                if (drawAnimation) {                    if (view != null) {                        view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;                    } else if (parent instanceof ViewRootImpl) {                        ((ViewRootImpl) parent).mIsAnimating = true;                    }                }                // 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.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;                    }                }                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);                        dirty.set((int) (boundingRect.left - 0.5f),                                (int) (boundingRect.top - 0.5f),                                (int) (boundingRect.right + 0.5f),                                (int) (boundingRect.bottom + 0.5f));                    }                }            } while (parent != null);        }    }
location数组设置了要绘制区域(dirty)的距离当前视图的左边界和上边界的距离,然后重点在do,while循环。parent = parent.invalidateChildInParent(location, dirty);

/**     * Don't call or override this method. It is used for the implementation of     * the view hierarchy.     *     * This implementation returns null if this ViewGroup does not have a parent,     * if this ViewGroup is already fully invalidated or if the dirty rectangle     * does not intersect with this ViewGroup's bounds.     */    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {        if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=                        FLAG_OPTIMIZE_INVALIDATE) {                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,                        location[CHILD_TOP_INDEX] - mScrollY);                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {                    dirty.union(0, 0, mRight - mLeft, mBottom - mTop);                }                final int left = mLeft;                final int top = mTop;                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {                    if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {                        dirty.setEmpty();                    }                }                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;                location[CHILD_LEFT_INDEX] = left;                location[CHILD_TOP_INDEX] = top;                if (mLayerType != LAYER_TYPE_NONE) {                    mPrivateFlags |= PFLAG_INVALIDATED;                    mLocalDirtyRect.union(dirty);                }                return mParent;            } else {                mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;                location[CHILD_LEFT_INDEX] = mLeft;                location[CHILD_TOP_INDEX] = mTop;                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {                    dirty.set(0, 0, mRight - mLeft, mBottom - mTop);                } else {                    // in case the dirty rect extends outside the bounds of this container                    dirty.union(0, 0, mRight - mLeft, mBottom - mTop);                }                if (mLayerType != LAYER_TYPE_NONE) {                    mPrivateFlags |= PFLAG_INVALIDATED;                    mLocalDirtyRect.union(dirty);                }                return mParent;            }        }        return null;    }

逻辑有点复杂,大概的思想就是循环计算dirty区域相对于俯视图的坐标,即先得到子视图的dirty的大小然后在父视图中根据子视图和子视图的dirty的大小计算这块dirty相对于父视图的位置,这里做了计算dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,location[CHILD_TOP_INDEX] - mScrollY);通过之前的do while循环,最终的到整块dirty区域相对于最外层view的位置。循环的最上层是ViewRoot。下面是ViewRoot的invalidateChildInParent

public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {        invalidateChild(null, dirty);        return null;    }
最终会return null

public void invalidateChild(View child, Rect dirty) {        checkThread();        if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);        if (mCurScrollY != 0 || mTranslator != null) {            mTempRect.set(dirty);            dirty = mTempRect;            if (mCurScrollY != 0) {               dirty.offset(0, -mCurScrollY);            }            if (mTranslator != null) {                mTranslator.translateRectInAppWindowToScreen(dirty);            }            if (mAttachInfo.mScalingRequired) {                dirty.inset(-1, -1);            }        }        mDirty.union(dirty);        if (!mWillDrawSoon) {            scheduleTraversals();        }    }


checkTread检查是不是UI线程。不是UI线程则报异常。最后执行sheduleTraversals, scheduleTraversals会发送一个异步消息,最终调用performTraversals()执行重绘。




更多相关文章

  1. Kotlin Android(安卓)Extensions 的未来计划
  2. 关于selector点击区域放大问题的解决
  3. View的刷新机制
  4. android 知识点总结 广播接收器生命周期【爱扒拉】
  5. Android中Activity布局及其加载
  6. Android自动滚动 轮播循环的ViewPager
  7. android popupwindow问题及里面的listview点击无效
  8. 【安卓学习总结】安卓开发
  9. 初学了解MVC在android中的应用

随机推荐

  1. Android(安卓)判断真机和模拟器的方法
  2. 通过自定义View,创建一个圆形指示器
  3. Fragment的API学习笔记
  4. Android的分辨率
  5. android初体验――HelloWord
  6. Android(安卓)Json的使用(1) 使用jsonschem
  7. Android中Activity之间的数据传递(Intent
  8. Android如何找到正确的ALSA底层kcontrol
  9. 给 Android(安卓)开发者的 Flutter 指南
  10. 阿拉伯语系处理方法