RecyclerView动画源码浅析

大城市里の小女人 提交于 2020-07-27 12:00:53

RecyclerView动画源码浅析
adapter.notifyItemRemoved(1)会回调到 RecyclerViewDataObserver:

adapter.notifyItemRemoved           RecyclerViewDataObserver

onItemRangeRemoved

triggerUpdateProcessor

mAdapterUpdateDuringMeasure

consumePendingUpdateOperations
dispatchLayout
dispatchLayoutStep1

processAdapterUpdatesAndSetAnimationFlags
preProcess

applyRemove
postponeAndUpdateViewHolders
offsetPositionsForRemovingLaidOutOrNewView
offsetPositionRecordsForRemove
flagRemovedAndOffsetPosition
setFrom
ItemHolderInfo ViewHolder mViewInfoStore  mLayoutHolderMap    保存动画前View的现场 






       if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
            }
            
            
              final Runnable mUpdateChildViewsRunnable = new Runnable() {
        @Override
        public void run() {
        
        
                    consumePendingUpdateOperations();
                    
                             dispatchLayout();
                             
                                dispatchLayoutStep1();















  @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            assertNotInLayoutOrScroll(null);
            if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
                triggerUpdateProcessor();
            }
        }







 mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));

    final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
    
    triggerUpdateProcessor()调用了requestLayout, 即触发了RecyclerView的重新布局。
    
    void triggerUpdateProcessor() {
            if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
            } else {
                mAdapterUpdateDuringMeasure = true;
                requestLayout();
            }
        }
        
            void dispatchLayout() {
               dispatchLayoutStep1();        
               processAdapterUpdatesAndSetAnimationFlags();
               
                     mAdapterHelper.preProcess();
                     
                      case UpdateOp.REMOVE:
                    applyRemove(op);
                    break;
            postponeAndUpdateViewHolders(op);





















      case UpdateOp.REMOVE:
                mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart,
                        op.itemCount);
                break;    


                

 void offsetPositionRecordsForRemove(int positionStart, int itemCount,
            boolean applyToPreLayout) {
            
            
                  holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount,
                            applyToPreLayout);
                    mState.mStructureChanged = true;
                    
                    flagRemovedAndOffsetPosition
            
            
            offsetPositionRecordsForRemove方法:主要是把当前显示在界面上的ViewHolder的位置做对应的改变,即如果item位于删除的item之后,那么它的位置应该减一,比如原来的位置是3现在变成了2。










RecyclerView                
                        @Override
            public void offsetPositionsForRemovingLaidOutOrNewView(
                    int positionStart, int itemCount) {
                offsetPositionRecordsForRemove(positionStart, itemCount, false);
                mItemsAddedOrRemoved = true;
            }





                    

    
     final ItemHolderInfo animationInfo
  @NonNull
            public ItemHolderInfo setFrom(@NonNull RecyclerView.ViewHolder holder,
                    @AdapterChanges int flags) {
                final View view = holder.itemView;
                this.left = view.getLeft();
                this.top = view.getTop();
                this.right = view.getRight();
                this.bottom = view.getBottom();
                return this;
            }











                    mViewInfoStore.addToPreLayout(holder, animationInfo);        
                    
                static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);            
                    
                    
                即把holder 和 info保存到 mLayoutHolderMap 中。可以理解为它是用来保存动画执行前当前界面ViewHolder的信息一个集合。






        @VisibleForTesting
    final ArrayMap<RecyclerView.ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();            
                    
    
其实这些操作可以简单的理解为保存动画前View的现场 





dispatchLayoutStep2

   // Step 2: Run layout
        mState.mInPreLayout = false;
        mLayout.onLayoutChildren(mRecycler, mState);
   fill(recycler, mLayoutState, state, false);


  layoutChunk(recycler, state, layoutState, layoutChunkResult);

   View view = layoutState.next(recycler);

       final View view = recycler.getViewForPosition(mCurrentPosition);

  return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;

dispatchLayoutStep3(执行删除动画)

    @VisibleForTesting
    final LongSparseArray<RecyclerView.ViewHolder> mOldChangedHolders = new LongSparseArray<>()

            // Step 4: Process view info lists and trigger animations
            mViewInfoStore.process(mViewInfoProcessCallback);


        private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
                    
                    
                        public void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo info,
                        @Nullable ItemHolderInfo postInfo) {
                    mRecycler.unscrapView(viewHolder);
                    animateDisappearance(viewHolder, info, postInfo);
                    
                    
                    
                  callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
                }    
                    
                    
                    
                    
                                        animateDisappearance(viewHolder, info, postInfo);
                    
                    
                    
                    
            addAnimatingView(holder);                
                    
               // re-attach
            mChildHelper.attachViewToParent(view, -1, view.getLayoutParams(), true);        
                    
                        if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) {    
                    
                  return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);        
                    
                    
           if (deltaX != 0) {
            view.setTranslationX(-deltaX);
        }
        if (deltaY != 0) {
            view.setTranslationY(-deltaY);
        }
        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));            
                    
            private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();            
                    
        将未被删除的Item的移动动画放入到mPendingMoves待执行队列









































       postAnimationRunner();


rivate Runnable mItemAnimatorRunner = new Runnable() {
        @Override


     mItemAnimator.runPendingAnimations();


   animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
                                moveInfo.toX, moveInfo.toY);

animateRemoveImpl 把这个被Remove的Item做一个透明度由(1~0)的动画
animateMoveImpl把它们的TranslationX和TranslationY移动到0的位置。

        
                    
                    

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!