android 动画原理源码分析之Animation

在开发移动应用程序的时候用到动画是家常便饭的事,但是你有没有想过它是怎么实现的呢?今天小弟就在此分析一下。

1 startAnimation 方法。

设置好animation变量,刷新父视图绘画缓存。

/*** Start the specified animation now.** @param animation the animation to start now*/public void startAnimation(Animation animation) {animation.setStartTime(Animation.START_ON_FIRST_FRAME);setAnimation(animation);invalidateParentCaches();invalidate(true);}2 invalidate

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,ConstantConditionsif (!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 everythingp.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 boundsp.invalidateChild(this, r);}}}由分析可知,将进入invalidateChild 方法。

3 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// throughfinal 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 timeint 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 invalidateif (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 parentMatrix 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);}}(首先来看这个方法是不允许重载的,为什么呢?在个人看来,这是出于对Android API的一种保护机制。这是视图刷新的人口。)

只有流过血的手指才能弹出世间的绝唱。

android 动画原理源码分析之Animation

相关文章:

你感兴趣的文章:

标签云: