Instantly share code, notes, and snippets.
CreatedJune 15, 2017 02:51
Save RareScrap/a720ffe4b9abeaf031ad9aab0e9d6d14 to your computer and use it in GitHub Desktop.
DefaultItemAnimator с подробным описанием (дополняется время от времени)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| /* | |
| * Copyright (C) 2014 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| packagecom.webtrust.tennosushi; | |
| importandroid.support.annotation.NonNull; | |
| importandroid.support.v4.animation.AnimatorCompatHelper; | |
| importandroid.support.v4.view.ViewCompat; | |
| importandroid.support.v4.view.ViewPropertyAnimatorCompat; | |
| importandroid.support.v4.view.ViewPropertyAnimatorListener; | |
| importandroid.support.v7.widget.CardView; | |
| importandroid.support.v7.widget.RecyclerView.ViewHolder; | |
| importandroid.support.v7.widget.SimpleItemAnimator; | |
| importandroid.view.View; | |
| importjava.util.ArrayList; | |
| importjava.util.List; | |
| /** | |
| * This implementation of {@link RecyclerView.ItemAnimator} provides basic | |
| * animations on remove, add, and move events that happen to the items in | |
| * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default. | |
| * | |
| * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator) | |
| */ | |
| publicclassDefaultItemAnimatorextendsSimpleItemAnimator { | |
| privatestaticfinalbooleanDEBUG =false; | |
| privateArrayList<ViewHolder>mPendingRemovals =newArrayList<>(); | |
| privateArrayList<ViewHolder>mPendingAdditions =newArrayList<>(); | |
| privateArrayList<MoveInfo>mPendingMoves =newArrayList<>(); | |
| privateArrayList<ChangeInfo>mPendingChanges =newArrayList<>(); | |
| ArrayList<ArrayList<ViewHolder>>mAdditionsList =newArrayList<>(); | |
| ArrayList<ArrayList<MoveInfo>>mMovesList =newArrayList<>(); | |
| ArrayList<ArrayList<ChangeInfo>>mChangesList =newArrayList<>(); | |
| ArrayList<ViewHolder>mAddAnimations =newArrayList<>(); | |
| ArrayList<ViewHolder>mMoveAnimations =newArrayList<>(); | |
| ArrayList<ViewHolder>mRemoveAnimations =newArrayList<>(); | |
| ArrayList<ViewHolder>mChangeAnimations =newArrayList<>(); | |
| privatestaticclassMoveInfo { | |
| publicViewHolderholder; | |
| publicintfromX,fromY,toX,toY; | |
| MoveInfo(ViewHolderholder,intfromX,intfromY,inttoX,inttoY) { | |
| this.holder =holder; | |
| this.fromX =fromX; | |
| this.fromY =fromY; | |
| this.toX =toX; | |
| this.toY =toY; | |
| } | |
| } | |
| privatestaticclassChangeInfo { | |
| publicViewHolderoldHolder,newHolder; | |
| publicintfromX,fromY,toX,toY; | |
| privateChangeInfo(ViewHolderoldHolder,ViewHoldernewHolder) { | |
| this.oldHolder =oldHolder; | |
| this.newHolder =newHolder; | |
| } | |
| ChangeInfo(ViewHolderoldHolder,ViewHoldernewHolder, | |
| intfromX,intfromY,inttoX,inttoY) { | |
| this(oldHolder,newHolder); | |
| this.fromX =fromX; | |
| this.fromY =fromY; | |
| this.toX =toX; | |
| this.toY =toY; | |
| } | |
| @Override | |
| publicStringtoString() { | |
| return"ChangeInfo{" + | |
| "oldHolder=" +oldHolder + | |
| ", newHolder=" +newHolder + | |
| ", fromX=" +fromX + | |
| ", fromY=" +fromY + | |
| ", toX=" +toX + | |
| ", toY=" +toY + | |
| '}'; | |
| } | |
| } | |
| @Override | |
| publicvoidrunPendingAnimations() { | |
| booleanremovalsPending = !mPendingRemovals.isEmpty(); | |
| booleanmovesPending = !mPendingMoves.isEmpty(); | |
| booleanchangesPending = !mPendingChanges.isEmpty(); | |
| booleanadditionsPending = !mPendingAdditions.isEmpty(); | |
| if (!removalsPending && !movesPending && !additionsPending && !changesPending) { | |
| // nothing to animate | |
| return; | |
| } | |
| // First, remove stuff | |
| for (ViewHolderholder :mPendingRemovals) { | |
| animateRemoveImpl(holder); | |
| } | |
| mPendingRemovals.clear(); | |
| // Next, move stuff | |
| if (movesPending) { | |
| finalArrayList<MoveInfo>moves =newArrayList<>(); | |
| moves.addAll(mPendingMoves); | |
| mMovesList.add(moves); | |
| mPendingMoves.clear(); | |
| Runnablemover =newRunnable() { | |
| @Override | |
| publicvoidrun() { | |
| for (MoveInfomoveInfo :moves) { | |
| animateMoveImpl(moveInfo.holder,moveInfo.fromX,moveInfo.fromY, | |
| moveInfo.toX,moveInfo.toY); | |
| } | |
| moves.clear(); | |
| mMovesList.remove(moves); | |
| } | |
| }; | |
| if (removalsPending) { | |
| Viewview =moves.get(0).holder.itemView; | |
| ViewCompat.postOnAnimationDelayed(view,mover,getRemoveDuration()); | |
| }else { | |
| mover.run(); | |
| } | |
| } | |
| // Next, change stuff, to run in parallel with move animations | |
| if (changesPending) { | |
| finalArrayList<ChangeInfo>changes =newArrayList<>(); | |
| changes.addAll(mPendingChanges); | |
| mChangesList.add(changes); | |
| mPendingChanges.clear(); | |
| Runnablechanger =newRunnable() { | |
| @Override | |
| publicvoidrun() { | |
| for (ChangeInfochange :changes) { | |
| animateChangeImpl(change); | |
| } | |
| changes.clear(); | |
| mChangesList.remove(changes); | |
| } | |
| }; | |
| if (removalsPending) { | |
| ViewHolderholder =changes.get(0).oldHolder; | |
| ViewCompat.postOnAnimationDelayed(holder.itemView,changer,getRemoveDuration()); | |
| }else { | |
| changer.run(); | |
| } | |
| } | |
| // Next, add stuff | |
| if (additionsPending) { | |
| finalArrayList<ViewHolder>additions =newArrayList<>(); | |
| additions.addAll(mPendingAdditions); | |
| mAdditionsList.add(additions); | |
| mPendingAdditions.clear(); | |
| Runnableadder =newRunnable() { | |
| @Override | |
| publicvoidrun() { | |
| for (ViewHolderholder :additions) { | |
| animateAddImpl(holder); | |
| } | |
| additions.clear(); | |
| mAdditionsList.remove(additions); | |
| } | |
| }; | |
| if (removalsPending ||movesPending ||changesPending) { | |
| longremoveDuration =removalsPending ?getRemoveDuration() :0; | |
| longmoveDuration =movesPending ?getMoveDuration() :0; | |
| longchangeDuration =changesPending ?getChangeDuration() :0; | |
| longtotalDelay =removeDuration +Math.max(moveDuration,changeDuration); | |
| Viewview =additions.get(0).itemView; | |
| ViewCompat.postOnAnimationDelayed(view,adder,totalDelay); | |
| }else { | |
| adder.run(); | |
| } | |
| } | |
| } | |
| // Отвечает за анимацию исчезаия "полного удаления" элемента | |
| @Override | |
| publicbooleananimateRemove(finalViewHolderholder) { | |
| resetAnimation(holder); | |
| mPendingRemovals.add(holder); | |
| returntrue; | |
| } | |
| privatevoidanimateRemoveImpl(finalViewHolderholder) { | |
| finalViewview =holder.itemView; | |
| finalViewPropertyAnimatorCompatanimation =ViewCompat.animate(view); | |
| mRemoveAnimations.add(holder); | |
| animation.setDuration(getRemoveDuration()) | |
| .alpha(0).setListener(newVpaListenerAdapter() { | |
| @Override | |
| publicvoidonAnimationStart(Viewview) { | |
| dispatchRemoveStarting(holder); | |
| } | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) { | |
| animation.setListener(null); | |
| ViewCompat.setAlpha(view,1); | |
| dispatchRemoveFinished(holder); | |
| mRemoveAnimations.remove(holder); | |
| dispatchFinishedWhenDone(); | |
| } | |
| }).start(); | |
| } | |
| @Override | |
| publicbooleananimateAdd(finalViewHolderholder) { | |
| resetAnimation(holder); | |
| ViewCompat.setAlpha(holder.itemView,0); | |
| mPendingAdditions.add(holder); | |
| returntrue; | |
| } | |
| voidanimateAddImpl(finalViewHolderholder) { | |
| finalViewview =holder.itemView; | |
| finalViewPropertyAnimatorCompatanimation =ViewCompat.animate(view); | |
| mAddAnimations.add(holder); | |
| animation.alpha(1).setDuration(getAddDuration()). | |
| setListener(newVpaListenerAdapter() { | |
| @Override | |
| publicvoidonAnimationStart(Viewview) { | |
| dispatchAddStarting(holder); | |
| } | |
| @Override | |
| publicvoidonAnimationCancel(Viewview) { | |
| ViewCompat.setAlpha(view,1); | |
| } | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) { | |
| animation.setListener(null); | |
| dispatchAddFinished(holder); | |
| mAddAnimations.remove(holder); | |
| dispatchFinishedWhenDone(); | |
| } | |
| }).start(); | |
| } | |
| // Отвечает за изменение высоты красного фона при свайпе, но не вызывается, если в списке всего один элемент | |
| @Override | |
| publicbooleananimateMove(finalViewHolderholder,intfromX,intfromY, | |
| inttoX,inttoY) { | |
| finalViewview =holder.itemView; | |
| fromX +=ViewCompat.getTranslationX(holder.itemView); | |
| fromY +=ViewCompat.getTranslationY(holder.itemView); | |
| resetAnimation(holder); | |
| intdeltaX =toX -fromX; | |
| intdeltaY =toY -fromY; | |
| if (deltaX ==0 &&deltaY ==0) { | |
| dispatchMoveFinished(holder); | |
| returnfalse; | |
| } | |
| if (deltaX !=0) { | |
| ViewCompat.setTranslationX(view, -deltaX); | |
| } | |
| if (deltaY !=0) { | |
| ViewCompat.setTranslationY(view, -deltaY); | |
| } | |
| mPendingMoves.add(newMoveInfo(holder,fromX,fromY,toX,toY)); | |
| returntrue; | |
| } | |
| voidanimateMoveImpl(finalViewHolderholder,intfromX,intfromY,inttoX,inttoY) { | |
| finalViewview =holder.itemView; | |
| finalintdeltaX =toX -fromX; | |
| finalintdeltaY =toY -fromY; | |
| if (deltaX !=0) { | |
| ViewCompat.animate(view).translationX(0); | |
| } | |
| if (deltaY !=0) { | |
| ViewCompat.animate(view).translationY(0); | |
| } | |
| // TODO: make EndActions end listeners instead, since end actions aren't called when | |
| // vpas are canceled (and can't end them. why?) | |
| // need listener functionality in VPACompat for this. Ick. | |
| finalViewPropertyAnimatorCompatanimation =ViewCompat.animate(view); | |
| mMoveAnimations.add(holder); | |
| animation.setDuration(getMoveDuration()).setListener(newVpaListenerAdapter() { | |
| @Override | |
| publicvoidonAnimationStart(Viewview) { | |
| dispatchMoveStarting(holder); | |
| } | |
| @Override | |
| publicvoidonAnimationCancel(Viewview) { | |
| if (deltaX !=0) { | |
| ViewCompat.setTranslationX(view,0); | |
| } | |
| if (deltaY !=0) { | |
| ViewCompat.setTranslationY(view,0); | |
| } | |
| } | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) { | |
| animation.setListener(null); | |
| dispatchMoveFinished(holder); | |
| mMoveAnimations.remove(holder); | |
| dispatchFinishedWhenDone(); | |
| } | |
| }).start(); | |
| } | |
| /** | |
| * В проекте TennoSushi Отвечает за анимацию "выдвижения" кнопки Undo (и, возможно, за что-то еще) | |
| * @param oldHolder Элемент списка, который подвергся изменению | |
| * @param newHolder Элемент списка, который получился из-за произошедших изменений | |
| * @param fromX Левый край oldHolder | |
| * @param fromY Вверхий край oldHolder | |
| * @param toX Левый край newHolder | |
| * @param toY Вверхий край newHolder | |
| * @return True, если позже ожидается (запрашивается) вызов {@link #runPendingAnimations()}, иначе - false | |
| */ | |
| @Override | |
| publicbooleananimateChange(ViewHolderoldHolder,ViewHoldernewHolder, | |
| intfromX,intfromY,inttoX,inttoY) { | |
| if (oldHolder ==newHolder) { | |
| // Don't know how to run change animations when the same view holder is re-used. | |
| // run a move animation to handle position changes. | |
| returnanimateMove(oldHolder,fromX,fromY,toX,toY); | |
| } | |
| // by RareScrap | |
| ( (CardView)oldHolder.itemView.findViewById(R.id.root_card_view)).setCardElevation(0); | |
| ( (CardView)newHolder.itemView.findViewById(R.id.root_card_view)).setCardElevation(0); | |
| finalfloatprevTranslationX =ViewCompat.getTranslationX(oldHolder.itemView); | |
| finalfloatprevTranslationY =ViewCompat.getTranslationY(oldHolder.itemView); | |
| finalfloatprevAlpha =ViewCompat.getAlpha(oldHolder.itemView); | |
| resetAnimation(oldHolder); | |
| intdeltaX = (int) (toX -fromX -prevTranslationX); | |
| intdeltaY = (int) (toY -fromY -prevTranslationY); | |
| // recover prev translation state after ending animation | |
| ViewCompat.setTranslationX(oldHolder.itemView,prevTranslationX); | |
| ViewCompat.setTranslationY(oldHolder.itemView,prevTranslationY); | |
| ViewCompat.setAlpha(oldHolder.itemView,prevAlpha); | |
| if (newHolder !=null) { | |
| // carry over translation values | |
| resetAnimation(newHolder); | |
| ViewCompat.setTranslationX(newHolder.itemView, -deltaX); | |
| ViewCompat.setTranslationY(newHolder.itemView, -deltaY); | |
| ViewCompat.setAlpha(newHolder.itemView,0); | |
| } | |
| mPendingChanges.add(newChangeInfo(oldHolder,newHolder,fromX,fromY,toX,toY)); | |
| returntrue; | |
| } | |
| voidanimateChangeImpl(finalChangeInfochangeInfo) { | |
| finalViewHolderholder =changeInfo.oldHolder; | |
| finalViewview =holder ==null ?null :holder.itemView; | |
| finalViewHoldernewHolder =changeInfo.newHolder; | |
| finalViewnewView =newHolder !=null ?newHolder.itemView :null; | |
| if (view !=null) { | |
| finalViewPropertyAnimatorCompatoldViewAnim =ViewCompat.animate(view).setDuration( | |
| getChangeDuration()); | |
| mChangeAnimations.add(changeInfo.oldHolder); | |
| oldViewAnim.translationX(changeInfo.toX -changeInfo.fromX); | |
| oldViewAnim.translationY(changeInfo.toY -changeInfo.fromY); | |
| oldViewAnim.alpha(0).setListener(newVpaListenerAdapter() { | |
| @Override | |
| publicvoidonAnimationStart(Viewview) { | |
| dispatchChangeStarting(changeInfo.oldHolder,true); | |
| } | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) { | |
| oldViewAnim.setListener(null); | |
| ViewCompat.setAlpha(view,1); | |
| ViewCompat.setTranslationX(view,0); | |
| ViewCompat.setTranslationY(view,0); | |
| dispatchChangeFinished(changeInfo.oldHolder,true); | |
| mChangeAnimations.remove(changeInfo.oldHolder); | |
| dispatchFinishedWhenDone(); | |
| } | |
| }).start(); | |
| } | |
| if (newView !=null) { | |
| finalViewPropertyAnimatorCompatnewViewAnimation =ViewCompat.animate(newView); | |
| mChangeAnimations.add(changeInfo.newHolder); | |
| newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). | |
| alpha(1).setListener(newVpaListenerAdapter() { | |
| @Override | |
| publicvoidonAnimationStart(Viewview) { | |
| dispatchChangeStarting(changeInfo.newHolder,false); | |
| } | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) { | |
| newViewAnimation.setListener(null); | |
| ViewCompat.setAlpha(newView,1); | |
| ViewCompat.setTranslationX(newView,0); | |
| ViewCompat.setTranslationY(newView,0); | |
| dispatchChangeFinished(changeInfo.newHolder,false); | |
| mChangeAnimations.remove(changeInfo.newHolder); | |
| dispatchFinishedWhenDone(); | |
| } | |
| }).start(); | |
| } | |
| } | |
| privatevoidendChangeAnimation(List<ChangeInfo>infoList,ViewHolderitem) { | |
| for (inti =infoList.size() -1;i >=0;i--) { | |
| ChangeInfochangeInfo =infoList.get(i); | |
| if (endChangeAnimationIfNecessary(changeInfo,item)) { | |
| if (changeInfo.oldHolder ==null &&changeInfo.newHolder ==null) { | |
| infoList.remove(changeInfo); | |
| } | |
| } | |
| } | |
| } | |
| privatevoidendChangeAnimationIfNecessary(ChangeInfochangeInfo) { | |
| if (changeInfo.oldHolder !=null) { | |
| endChangeAnimationIfNecessary(changeInfo,changeInfo.oldHolder); | |
| } | |
| if (changeInfo.newHolder !=null) { | |
| endChangeAnimationIfNecessary(changeInfo,changeInfo.newHolder); | |
| } | |
| } | |
| privatebooleanendChangeAnimationIfNecessary(ChangeInfochangeInfo,ViewHolderitem) { | |
| booleanoldItem =false; | |
| if (changeInfo.newHolder ==item) { | |
| changeInfo.newHolder =null; | |
| }elseif (changeInfo.oldHolder ==item) { | |
| changeInfo.oldHolder =null; | |
| oldItem =true; | |
| }else { | |
| returnfalse; | |
| } | |
| ViewCompat.setAlpha(item.itemView,1); | |
| ViewCompat.setTranslationX(item.itemView,0); | |
| ViewCompat.setTranslationY(item.itemView,0); | |
| dispatchChangeFinished(item,oldItem); | |
| returntrue; | |
| } | |
| @Override | |
| publicvoidendAnimation(ViewHolderitem) { | |
| finalViewview =item.itemView; | |
| // this will trigger end callback which should set properties to their target values. | |
| ViewCompat.animate(view).cancel(); | |
| // TODO if some other animations are chained to end, how do we cancel them as well? | |
| for (inti =mPendingMoves.size() -1;i >=0;i--) { | |
| MoveInfomoveInfo =mPendingMoves.get(i); | |
| if (moveInfo.holder ==item) { | |
| ViewCompat.setTranslationY(view,0); | |
| ViewCompat.setTranslationX(view,0); | |
| dispatchMoveFinished(item); | |
| mPendingMoves.remove(i); | |
| } | |
| } | |
| endChangeAnimation(mPendingChanges,item); | |
| if (mPendingRemovals.remove(item)) { | |
| ViewCompat.setAlpha(view,1); | |
| dispatchRemoveFinished(item); | |
| } | |
| if (mPendingAdditions.remove(item)) { | |
| ViewCompat.setAlpha(view,1); | |
| dispatchAddFinished(item); | |
| } | |
| for (inti =mChangesList.size() -1;i >=0;i--) { | |
| ArrayList<ChangeInfo>changes =mChangesList.get(i); | |
| endChangeAnimation(changes,item); | |
| if (changes.isEmpty()) { | |
| mChangesList.remove(i); | |
| } | |
| } | |
| for (inti =mMovesList.size() -1;i >=0;i--) { | |
| ArrayList<MoveInfo>moves =mMovesList.get(i); | |
| for (intj =moves.size() -1;j >=0;j--) { | |
| MoveInfomoveInfo =moves.get(j); | |
| if (moveInfo.holder ==item) { | |
| ViewCompat.setTranslationY(view,0); | |
| ViewCompat.setTranslationX(view,0); | |
| dispatchMoveFinished(item); | |
| moves.remove(j); | |
| if (moves.isEmpty()) { | |
| mMovesList.remove(i); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| for (inti =mAdditionsList.size() -1;i >=0;i--) { | |
| ArrayList<ViewHolder>additions =mAdditionsList.get(i); | |
| if (additions.remove(item)) { | |
| ViewCompat.setAlpha(view,1); | |
| dispatchAddFinished(item); | |
| if (additions.isEmpty()) { | |
| mAdditionsList.remove(i); | |
| } | |
| } | |
| } | |
| // animations should be ended by the cancel above. | |
| //noinspection PointlessBooleanExpression,ConstantConditions | |
| if (mRemoveAnimations.remove(item) &&DEBUG) { | |
| thrownewIllegalStateException("after animation is cancelled, item should not be in " | |
| +"mRemoveAnimations list"); | |
| } | |
| //noinspection PointlessBooleanExpression,ConstantConditions | |
| if (mAddAnimations.remove(item) &&DEBUG) { | |
| thrownewIllegalStateException("after animation is cancelled, item should not be in " | |
| +"mAddAnimations list"); | |
| } | |
| //noinspection PointlessBooleanExpression,ConstantConditions | |
| if (mChangeAnimations.remove(item) &&DEBUG) { | |
| thrownewIllegalStateException("after animation is cancelled, item should not be in " | |
| +"mChangeAnimations list"); | |
| } | |
| //noinspection PointlessBooleanExpression,ConstantConditions | |
| if (mMoveAnimations.remove(item) &&DEBUG) { | |
| thrownewIllegalStateException("after animation is cancelled, item should not be in " | |
| +"mMoveAnimations list"); | |
| } | |
| dispatchFinishedWhenDone(); | |
| } | |
| privatevoidresetAnimation(ViewHolderholder) { | |
| AnimatorCompatHelper.clearInterpolator(holder.itemView); | |
| endAnimation(holder); | |
| } | |
| @Override | |
| publicbooleanisRunning() { | |
| return (!mPendingAdditions.isEmpty() || | |
| !mPendingChanges.isEmpty() || | |
| !mPendingMoves.isEmpty() || | |
| !mPendingRemovals.isEmpty() || | |
| !mMoveAnimations.isEmpty() || | |
| !mRemoveAnimations.isEmpty() || | |
| !mAddAnimations.isEmpty() || | |
| !mChangeAnimations.isEmpty() || | |
| !mMovesList.isEmpty() || | |
| !mAdditionsList.isEmpty() || | |
| !mChangesList.isEmpty()); | |
| } | |
| /** | |
| * Check the state of currently pending and running animations. If there are none | |
| * pending/running, call {@link #dispatchAnimationsFinished()} to notify any | |
| * listeners. | |
| */ | |
| voiddispatchFinishedWhenDone() { | |
| if (!isRunning()) { | |
| dispatchAnimationsFinished(); | |
| } | |
| } | |
| @Override | |
| publicvoidendAnimations() { | |
| intcount =mPendingMoves.size(); | |
| for (inti =count -1;i >=0;i--) { | |
| MoveInfoitem =mPendingMoves.get(i); | |
| Viewview =item.holder.itemView; | |
| ViewCompat.setTranslationY(view,0); | |
| ViewCompat.setTranslationX(view,0); | |
| dispatchMoveFinished(item.holder); | |
| mPendingMoves.remove(i); | |
| } | |
| count =mPendingRemovals.size(); | |
| for (inti =count -1;i >=0;i--) { | |
| ViewHolderitem =mPendingRemovals.get(i); | |
| dispatchRemoveFinished(item); | |
| mPendingRemovals.remove(i); | |
| } | |
| count =mPendingAdditions.size(); | |
| for (inti =count -1;i >=0;i--) { | |
| ViewHolderitem =mPendingAdditions.get(i); | |
| Viewview =item.itemView; | |
| ViewCompat.setAlpha(view,1); | |
| dispatchAddFinished(item); | |
| mPendingAdditions.remove(i); | |
| } | |
| count =mPendingChanges.size(); | |
| for (inti =count -1;i >=0;i--) { | |
| endChangeAnimationIfNecessary(mPendingChanges.get(i)); | |
| } | |
| mPendingChanges.clear(); | |
| if (!isRunning()) { | |
| return; | |
| } | |
| intlistCount =mMovesList.size(); | |
| for (inti =listCount -1;i >=0;i--) { | |
| ArrayList<MoveInfo>moves =mMovesList.get(i); | |
| count =moves.size(); | |
| for (intj =count -1;j >=0;j--) { | |
| MoveInfomoveInfo =moves.get(j); | |
| ViewHolderitem =moveInfo.holder; | |
| Viewview =item.itemView; | |
| ViewCompat.setTranslationY(view,0); | |
| ViewCompat.setTranslationX(view,0); | |
| dispatchMoveFinished(moveInfo.holder); | |
| moves.remove(j); | |
| if (moves.isEmpty()) { | |
| mMovesList.remove(moves); | |
| } | |
| } | |
| } | |
| listCount =mAdditionsList.size(); | |
| for (inti =listCount -1;i >=0;i--) { | |
| ArrayList<ViewHolder>additions =mAdditionsList.get(i); | |
| count =additions.size(); | |
| for (intj =count -1;j >=0;j--) { | |
| ViewHolderitem =additions.get(j); | |
| Viewview =item.itemView; | |
| ViewCompat.setAlpha(view,1); | |
| dispatchAddFinished(item); | |
| additions.remove(j); | |
| if (additions.isEmpty()) { | |
| mAdditionsList.remove(additions); | |
| } | |
| } | |
| } | |
| listCount =mChangesList.size(); | |
| for (inti =listCount -1;i >=0;i--) { | |
| ArrayList<ChangeInfo>changes =mChangesList.get(i); | |
| count =changes.size(); | |
| for (intj =count -1;j >=0;j--) { | |
| endChangeAnimationIfNecessary(changes.get(j)); | |
| if (changes.isEmpty()) { | |
| mChangesList.remove(changes); | |
| } | |
| } | |
| } | |
| cancelAll(mRemoveAnimations); | |
| cancelAll(mMoveAnimations); | |
| cancelAll(mAddAnimations); | |
| cancelAll(mChangeAnimations); | |
| dispatchAnimationsFinished(); | |
| } | |
| voidcancelAll(List<ViewHolder>viewHolders) { | |
| for (inti =viewHolders.size() -1;i >=0;i--) { | |
| ViewCompat.animate(viewHolders.get(i).itemView).cancel(); | |
| } | |
| } | |
| /** | |
| * {@inheritDoc} | |
| * <p> | |
| * If the payload list is not empty, DefaultItemAnimator returns <code>true</code>. | |
| * When this is the case: | |
| * <ul> | |
| * <li>If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both | |
| * ViewHolder arguments will be the same instance. | |
| * </li> | |
| * <li> | |
| * If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, | |
| * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and | |
| * run a move animation instead. | |
| * </li> | |
| * </ul> | |
| */ | |
| @Override | |
| publicbooleancanReuseUpdatedViewHolder(@NonNullViewHolderviewHolder, | |
| @NonNullList<Object>payloads) { | |
| return !payloads.isEmpty() ||super.canReuseUpdatedViewHolder(viewHolder,payloads); | |
| } | |
| privatestaticclassVpaListenerAdapterimplementsViewPropertyAnimatorListener { | |
| VpaListenerAdapter() { | |
| } | |
| @Override | |
| publicvoidonAnimationStart(Viewview) {} | |
| @Override | |
| publicvoidonAnimationEnd(Viewview) {} | |
| @Override | |
| publicvoidonAnimationCancel(Viewview) {} | |
| } | |
| } |
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment