RecyclerView.java源码动画分析,每个itemView的动画交给了 DefaultItemAnimator 这个类进行处理

dispatchLayout()
Step1就是pre layout 预布局–item信息存入preInfo,
Step2就是真正测量和布局,
Step3就是post layout 后布局–item信息存入postInfo

Step4
就是 
消失动画和删除条目,
Step5
就是
展现
动画和增加条目

当数据集发生变化时,会导致RecyclerView重新测量&布局子控件,我们记录下这个变化前后的RecyclerView的快照(preInfo与postInfo),通过比较这2个快照,从而确定子控件要执行什么操作,最后再实现不同操作下对应的动画就好了。通常我们会调用notifyItemXXX()系列方法来通知RecyclerView数据集变化,这些方法之所以比notifyDataSetChanged()高效的原因就是它们不会让整个RecyclerView重新绘制,而是只重绘具体的子控件,并且通过动画连接子控件的前后状态,这样也就实现了在Material design中所讲的“Visual continuity”效果。

/**
 * Wrapper around layoutChildren() that handles animating changes caused by layout.
 * Animations work on the assumption that there are five different kinds of items
 * in play:
 * PERSISTENT: items are visible before and after layout
 * REMOVED: items were visible before layout and were removed by the app
 * ADDED: items did not exist before layout and were added by the app
 * DISAPPEARING: items exist in the data set before/after, but changed from
 * visible to non-visible in the process of layout (they were moved off
 * screen as a side-effect of other changes)
 * APPEARING: items exist in the data set before/after, but changed from
 * non-visible to visible in the process of layout (they were moved on
 * screen as a side-effect of other changes)
 * The overall approach figures out what items exist before/after layout and
 * infers one of the five above states for each of the items. Then the animations
 * are set up accordingly:
 * PERSISTENT views are moved ({@link ItemAnimator#animateMove(ViewHolder, int, int, int, int)})
 * REMOVED views are removed ({@link ItemAnimator#animateRemove(ViewHolder)})
 * ADDED views are added ({@link ItemAnimator#animateAdd(ViewHolder)})
 * DISAPPEARING views are moved off screen
 * APPEARING views are moved on screen
 */
void dispatchLayout() {
    if (mAdapter == null) {
        Log.e(TAG, "No adapter attached; skipping layout");
        return;
    }
    if (mLayout == null) {
        Log.e(TAG, "No layout manager attached; skipping layout");
        return;
    }
    mState.mDisappearingViewsInLayoutPass.clear();
    eatRequestLayout();
    onEnterLayoutOrScroll();

    processAdapterUpdatesAndSetAnimationFlags();

    mState.mOldChangedHolders = mState.mRunSimpleAnimations && mItemsChanged
            && supportsChangeAnimations() ? new ArrayMap<Long, ViewHolder>() : null;
    mItemsAddedOrRemoved = mItemsChanged = false;
    ArrayMap<View, Rect> appearingViewInitialBounds = null;
    mState.mInPreLayout = mState.mRunPredictiveAnimations;
    mState.mItemCount = mAdapter.getItemCount();
    findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);

    if (mState.mRunSimpleAnimations) {
        // Step 0: Find out where all non-removed items are, pre-layout找到所有没有删除的items,预布局.
        mState.mPreLayoutHolderMap.clear();
        mState.mPostLayoutHolderMap.clear();
        int count = mChildHelper.getChildCount();
        for (int i = 0; i < count; ++i) {
            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
            if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) {
                continue;
            }
            final View view = holder.itemView;
            mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
                    view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
        }
    }
    if (mState.mRunPredictiveAnimations) {
// Step 1: 运行预布局.run prelayout: This will use the old positions of items. The layout manager is expected to layout everything, even removed items (though not to add removed items back to the container). This gives the pre-layout position of APPEARING views which come into existence as part of the real layout.

        // Save old positions so that LayoutManager can run its mapping logic.
        saveOldPositions();
        // processAdapterUpdatesAndSetAnimationFlags already run pre-layout animations.
        if (mState.mOldChangedHolders != null) {
            int count = mChildHelper.getChildCount();
            for (int i = 0; i < count; ++i) {
                final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
                    long key = getChangedHolderKey(holder);
                    mState.mOldChangedHolders.put(key, holder);
                    mState.mPreLayoutHolderMap.remove(holder);
                }
            }
        }

        final boolean didStructureChange = mState.mStructureChanged;
        mState.mStructureChanged = false;
        // temporarily disable flag because we are asking for previous layout
        mLayout.onLayoutChildren(mRecycler, mState);
        mState.mStructureChanged = didStructureChange;

        appearingViewInitialBounds = new ArrayMap<View, Rect>();
        for (int i = 0; i < mChildHelper.getChildCount(); ++i) {
            boolean found = false;
            View child = mChildHelper.getChildAt(i);
            if (getChildViewHolderInt(child).shouldIgnore()) {
                continue;
            }
            for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
                ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
                if (holder.itemView == child) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(),
                        child.getRight(), child.getBottom()));
            }
        }
        // we don't process disappearing list because they may re-appear in post layout pass.
        clearOldPositions();
        mAdapterHelper.consumePostponedUpdates();
    } else {
        clearOldPositions();
        // in case pre layout did run but we decided not to run predictive animations.
        mAdapterHelper.consumeUpdatesInOnePass();
        if (mState.mOldChangedHolders != null) {
            int count = mChildHelper.getChildCount();
            for (int i = 0; i < count; ++i) {
                final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
                    long key = getChangedHolderKey(holder);
                    mState.mOldChangedHolders.put(key, holder);
                    mState.mPreLayoutHolderMap.remove(holder);
                }
            }
        }
    }
    mState.mItemCount = mAdapter.getItemCount();
    mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;

    // Step 2: Run layout开始布局
    mState.mInPreLayout = false;
    mLayout.onLayoutChildren(mRecycler, mState);

    mState.mStructureChanged = false;
    mPendingSavedState = null;

    // onLayoutChildren may have caused client code to disable item animations; re-check
    mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;

    if (mState.mRunSimpleAnimations) {
        // Step 3: 找到现在所有的条目的位置,布局之后Find out where things are now, post-layout
        ArrayMap<Long, ViewHolder> newChangedHolders = mState.mOldChangedHolders != null ?
                new ArrayMap<Long, ViewHolder>() : null;
        int count = mChildHelper.getChildCount();
        for (int i = 0; i < count; ++i) {
            ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
            if (holder.shouldIgnore()) {
                continue;
            }
            final View view = holder.itemView;
            long key = getChangedHolderKey(holder);
            if (newChangedHolders != null && mState.mOldChangedHolders.get(key) != null) {
                newChangedHolders.put(key, holder);
            } else {
                mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
                        view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
            }
        }
        processDisappearingList(appearingViewInitialBounds);
        // Step 4:消失动画和删除条目 Animate DISAPPEARING and REMOVED items
        int preLayoutCount = mState.mPreLayoutHolderMap.size();
        for (int i = preLayoutCount - 1; i >= 0; i--) {
            ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
            if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
                ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
                mState.mPreLayoutHolderMap.removeAt(i);

                View disappearingItemView = disappearingItem.holder.itemView;
                mRecycler.unscrapView(disappearingItem.holder);
                animateDisappearance(disappearingItem);
            }
        }
        // Step 5: 展现动画和增加条目Animate APPEARING and ADDED items
        int postLayoutCount = mState.mPostLayoutHolderMap.size();
        if (postLayoutCount > 0) {
            for (int i = postLayoutCount - 1; i >= 0; i--) {
                ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
                ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
                if ((mState.mPreLayoutHolderMap.isEmpty() ||
                        !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
                    mState.mPostLayoutHolderMap.removeAt(i);
                    Rect initialBounds = (appearingViewInitialBounds != null) ?
                            appearingViewInitialBounds.get(itemHolder.itemView) : null;
                    animateAppearance(itemHolder, initialBounds,
                            info.left, info.top);
                }
            }
        }
        // Step 6: 持久的条目 的动画Animate PERSISTENT items
        count = mState.mPostLayoutHolderMap.size();
        for (int i = 0; i < count; ++i) {
            ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
            ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
            ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
            if (preInfo != null && postInfo != null) {
                if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
                    postHolder.setIsRecyclable(false);
                    if (DEBUG) {
                        Log.d(TAG, "PERSISTENT: " + postHolder +
                                " with view " + postHolder.itemView);
                    }
                    if (mItemAnimator.animateMove(postHolder,
                            preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
                        postAnimationRunner();
                    }
                }
            }
        }
        // Step 7: 改变条目的 动画Animate CHANGING items
        count = mState.mOldChangedHolders != null ? mState.mOldChangedHolders.size() : 0;
        // traverse reverse in case view gets recycled while we are traversing the list.
        for (int i = count - 1; i >= 0; i--) {
            long key = mState.mOldChangedHolders.keyAt(i);
            ViewHolder oldHolder = mState.mOldChangedHolders.get(key);
            View oldView = oldHolder.itemView;
            if (oldHolder.shouldIgnore()) {
                continue;
            }
            // We probably don't need this check anymore since these views are removed from
            // the list if they are recycled.
            if (mRecycler.mChangedScrap != null &&
                    mRecycler.mChangedScrap.contains(oldHolder)) {
                animateChange(oldHolder, newChangedHolders.get(key));
            } else if (DEBUG) {
                Log.e(TAG, "cannot find old changed holder in changed scrap :/" + oldHolder);
            }
        }
    }
    resumeRequestLayout(false);
    mLayout.removeAndRecycleScrapInt(mRecycler);
    mState.mPreviousLayoutItemCount = mState.mItemCount;
    mDataSetHasChangedAfterLayout = false;
    mState.mRunSimpleAnimations = false;
    mState.mRunPredictiveAnimations = false;
    onExitLayoutOrScroll();
    mLayout.mRequestedSimpleAnimations = false;
    if (mRecycler.mChangedScrap != null) {
        mRecycler.mChangedScrap.clear();
    }
    mState.mOldChangedHolders = null;

    if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
        dispatchOnScrolled(0, 0);
    }
}


  至于每个itemView的动画交给了  DefaultItemAnimator 这个类进行处理,不停的更新的动画itemView的位置或者是透明度以及其他的数据。

   主要的逻辑就是:

       增加/删除itemView –  保留itemView 的位置 -进行预处理(测量所有itemView的位置),获取新增的itemView-   清除所有itemView的位置信息-  测量以及定位所有的itemView- 保存itemview的最终动画的位置以及其他信息- 处理删除remove的itemView- 处理被add的itemview的动画-处理剩余itemview 位置改变的itemview的动画。


    原文作者:hzw05103020
    原文地址: https://blog.csdn.net/hzw05103020/article/details/53041014
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞