- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
- if (p != null && ai != null && ai.mHardwareAccelerated) {
- p.invalidateChild(this, null);
- return;
- }
- }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- p.invalidateChild(this, r);
- }
- }
- }
- public final void invalidateChild(View child, final Rect dirty) {
- ViewParent parent = this;
- final AttachInfo attachInfo = mAttachInfo;
- if (attachInfo != null) {
- final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
- if (dirty == null) {
- ......
- } else {
- ......
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- if (view.mLayerType != LAYER_TYPE_NONE &&
- view.getParent() instanceof View) {
- final View grandParent = (View) view.getParent();
- grandParent.mPrivateFlags |= INVALIDATED;
- grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- }
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).mIsAnimating = true;
- }
- }
- if (view != null) {
- if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
- view.getSolidColor() == 0) {
- opaqueFlag = DIRTY;
- }
- if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
- view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
- }
- }
- parent = parent.invalidateChildInParent(location, dirty);
- if (view != null) {
- Matrix m = view.getMatrix();
- if (!m.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- m.mapRect(boundingRect);
- dirty.set((int) boundingRect.left, (int) boundingRect.top,
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
- }
- }
- } while (parent != null);
- }
- }
- }
- public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
- invalidateChild(null, dirty);
- return null;
- }
- public void invalidateChild(View child, Rect dirty) {
- checkThread();
- if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
- mDirty.union(dirty);
- if (!mWillDrawSoon) {
- scheduleTraversals();
- }
- }
- public void scheduleTraversals() {
- if (!mTraversalScheduled) {
- mTraversalScheduled = true;
- sendEmptyMessage(DO_TRAVERSAL);
- }
- }
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case DO_TRAVERSAL:
- if (mProfile) {
- Debug.startMethodTracing("ViewRoot");
- }
- performTraversals();
- if (mProfile) {
- Debug.stopMethodTracing();
- mProfile = false;
- }
- break;
- ......
- }
熟悉的代码出现了!这里在第7行调用了performTraversals()方法,这不就是我们在前面一篇文章中学到的视图绘制的入口吗?虽然经过了很多辗转的调用,但是可以确定的是,调用视图的invalidate()方法后确实会走到performTraversals()方法中,然后重新执行绘制流程。之后的流程就不需要再进行描述了吧,可以参考Android视图绘制流程完全解析,带你一步步深入了解View(二) 这一篇文章。
了解了这些之后,我们再回过头来看看刚才的selectDrawable()方法中到底做了什么才能够控制背景图的改变,代码如下所示:
- public boolean selectDrawable(int idx) {
- if (idx == mCurIndex) {
- return false;
- }
- final long now = SystemClock.uptimeMillis();
- if (mDrawableContainerState.mExitFadeDuration > 0) {
- if (mLastDrawable != null) {
- mLastDrawable.setVisible(false, false);
- }
- if (mCurrDrawable != null) {
- mLastDrawable = mCurrDrawable;
- mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration;
- } else {
- mLastDrawable = null;
- mExitAnimationEnd = 0;
- }
- } else if (mCurrDrawable != null) {
- mCurrDrawable.setVisible(false, false);
- }
- if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
- Drawable d = mDrawableContainerState.mDrawables[idx];
- mCurrDrawable = d;
- mCurIndex = idx;
- if (d != null) {
- if (mDrawableContainerState.mEnterFadeDuration > 0) {
- mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
- } else {
- d.setAlpha(mAlpha);
- }
- d.setVisible(isVisible(), true);
- d.setDither(mDrawableContainerState.mDither);
- d.setColorFilter(mColorFilter);
- d.setState(getState());
- d.setLevel(getLevel());
- d.setBounds(getBounds());
- }
- } else {
- mCurrDrawable = null;
- mCurIndex = -1;
- }
- if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) {
- if (mAnimationRunnable == null) {
- mAnimationRunnable = new Runnable() {
- @Override public void run() {
- animate(true);
- invalidateSelf();
- }
- };
- } else {
- unscheduleSelf(mAnimationRunnable);
- }
- animate(true);
- }
- invalidateSelf();
- return true;
- }
- public void invalidateSelf() {
- final Callback callback = getCallback();
- if (callback != null) {
- callback.invalidateDrawable(this);
- }
- }
- public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback,
- AccessibilityEventSource {
- ......
- }
另外需要注意的是,invalidate()方法虽然最终会调用到performTraversals()方法中,但这时measure和layout流程是不会重新执行的,因为视图没有强制重新测量的标志位,而且大小也没有发生过变化,所以这时只有draw流程可以得到执行。而如果你希望视图的绘制流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而应该调用requestLayout()了。这个方法中的流程比invalidate()方法要简单一些,但中心思想是差不多的,这里也就不再详细进行分析了。
这样的话,我们就将视图状态以及重绘的工作原理都搞清楚了,相信大家对View的理解变得更加深刻了。感兴趣的朋友可以继续阅读 Android自定义View的实现方法,带你一步步深入了解View(四) 。
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
- if (p != null && ai != null && ai.mHardwareAccelerated) {
- p.invalidateChild(this, null);
- return;
- }
- }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- p.invalidateChild(this, r);
- }
- }
- }
- public final void invalidateChild(View child, final Rect dirty) {
- ViewParent parent = this;
- final AttachInfo attachInfo = mAttachInfo;
- if (attachInfo != null) {
- final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
- if (dirty == null) {
- ......
- } else {
- ......
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- if (view.mLayerType != LAYER_TYPE_NONE &&
- view.getParent() instanceof View) {
- final View grandParent = (View) view.getParent();
- grandParent.mPrivateFlags |= INVALIDATED;
- grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- }
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).mIsAnimating = true;
- }
- }
- if (view != null) {
- if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
- view.getSolidColor() == 0) {
- opaqueFlag = DIRTY;
- }
- if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
- view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
- }
- }
- parent = parent.invalidateChildInParent(location, dirty);
- if (view != null) {
- Matrix m = view.getMatrix();
- if (!m.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- m.mapRect(boundingRect);
- dirty.set((int) boundingRect.left, (int) boundingRect.top,
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
- }
- }
- } while (parent != null);
- }
- }
- }
- public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
- invalidateChild(null, dirty);
- return null;
- }
- public void invalidateChild(View child, Rect dirty) {
- checkThread();
- if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
- mDirty.union(dirty);
- if (!mWillDrawSoon) {
- scheduleTraversals();
- }
- }
- public void scheduleTraversals() {
- if (!mTraversalScheduled) {
- mTraversalScheduled = true;
- sendEmptyMessage(DO_TRAVERSAL);
- }
- }
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case DO_TRAVERSAL:
- if (mProfile) {
- Debug.startMethodTracing("ViewRoot");
- }
- performTraversals();
- if (mProfile) {
- Debug.stopMethodTracing();
- mProfile = false;
- }
- break;
- ......
- }
熟悉的代码出现了!这里在第7行调用了performTraversals()方法,这不就是我们在前面一篇文章中学到的视图绘制的入口吗?虽然经过了很多辗转的调用,但是可以确定的是,调用视图的invalidate()方法后确实会走到performTraversals()方法中,然后重新执行绘制流程。之后的流程就不需要再进行描述了吧,可以参考Android视图绘制流程完全解析,带你一步步深入了解View(二) 这一篇文章。
了解了这些之后,我们再回过头来看看刚才的selectDrawable()方法中到底做了什么才能够控制背景图的改变,代码如下所示:
- public boolean selectDrawable(int idx) {
- if (idx == mCurIndex) {
- return false;
- }
- final long now = SystemClock.uptimeMillis();
- if (mDrawableContainerState.mExitFadeDuration > 0) {
- if (mLastDrawable != null) {
- mLastDrawable.setVisible(false, false);
- }
- if (mCurrDrawable != null) {
- mLastDrawable = mCurrDrawable;
- mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration;
- } else {
- mLastDrawable = null;
- mExitAnimationEnd = 0;
- }
- } else if (mCurrDrawable != null) {
- mCurrDrawable.setVisible(false, false);
- }
- if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
- Drawable d = mDrawableContainerState.mDrawables[idx];
- mCurrDrawable = d;
- mCurIndex = idx;
- if (d != null) {
- if (mDrawableContainerState.mEnterFadeDuration > 0) {
- mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
- } else {
- d.setAlpha(mAlpha);
- }
- d.setVisible(isVisible(), true);
- d.setDither(mDrawableContainerState.mDither);
- d.setColorFilter(mColorFilter);
- d.setState(getState());
- d.setLevel(getLevel());
- d.setBounds(getBounds());
- }
- } else {
- mCurrDrawable = null;
- mCurIndex = -1;
- }
- if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) {
- if (mAnimationRunnable == null) {
- mAnimationRunnable = new Runnable() {
- @Override public void run() {
- animate(true);
- invalidateSelf();
- }
- };
- } else {
- unscheduleSelf(mAnimationRunnable);
- }
- animate(true);
- }
- invalidateSelf();
- return true;
- }
- public void invalidateSelf() {
- final Callback callback = getCallback();
- if (callback != null) {
- callback.invalidateDrawable(this);
- }
- }
- public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback,
- AccessibilityEventSource {
- ......
- }
另外需要注意的是,invalidate()方法虽然最终会调用到performTraversals()方法中,但这时measure和layout流程是不会重新执行的,因为视图没有强制重新测量的标志位,而且大小也没有发生过变化,所以这时只有draw流程可以得到执行。而如果你希望视图的绘制流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而应该调用requestLayout()了。这个方法中的流程比invalidate()方法要简单一些,但中心思想是差不多的,这里也就不再详细进行分析了。
这样的话,我们就将视图状态以及重绘的工作原理都搞清楚了,相信大家对View的理解变得更加深刻了。感兴趣的朋友可以继续阅读 Android自定义View的实现方法,带你一步步深入了解View(四) 。