为了让RecyclerView更加用户友好,可以给条目添加动画,RecyclerView可以设置条目动画
设置条目动画的代码是:
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
可以给RecyclerView设置一个默认的动画,使用默认动画的话可以给条目设置动画时间
DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
defaultItemAnimator.setRemoveDuration(200);
defaultItemAnimator.setAddDuration(200);
defaultItemAnimator.setMoveDuration(200);
defaultItemAnimator.setChangeDuration(200);
mRecyclerView.setItemAnimator(defaultItemAnimator);
另外,还可以自定义一个动画,这样就需要深入研究DefaultItemAnimator
类了。
DefaultItemAnimator
的最终父类是ItemAnimator
,该类是RecyclerView的内部抽象类,根据它抽象的特性,我们可以自定义ItemAnimator
,当然,如果这样的话就比较复杂了,因此,就自定义DefaultItemAnimator
了。
public class MyCustomItemAnimator extends DefaultItemAnimator {
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
//删除条目动画实现
return super.animateRemove(holder);
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
//添加条目动画实现
return super.animateAdd(holder);
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
//移动条目动画实现
return super.animateMove(holder, fromX, fromY, toX, toY);
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
//改变条目动画实现
return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
}
}
如上代码,动画的实现主要体现在animateRemove
、animateAdd
、animateMove
、animateChange
这四个方法。
在不做修改的情况下,条目动画都是默认的,想要学会自定义动画,那么首先需要研究下DefaultItemAnimator类的源码。
研究源码后发现,当触发添加条目动作时会执行
public boolean animateAdd(ViewHolder holder) {
this.resetAnimation(holder);
holder.itemView.setAlpha(0.0F);
this.mPendingAdditions.add(holder);
return true;
}
当触发条目移动动作时执行
public boolean animateMove(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
View view = holder.itemView;
fromX += (int)holder.itemView.getTranslationX();
fromY += (int)holder.itemView.getTranslationY();
this.resetAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
this.dispatchMoveFinished(holder);
return false;
} else {
if (deltaX != 0) {
view.setTranslationX((float)(-deltaX));
}
if (deltaY != 0) {
view.setTranslationY((float)(-deltaY));
}
this.mPendingMoves.add(new DefaultItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
}
当触发条目删除时执行
public boolean animateRemove(ViewHolder holder) {
this.resetAnimation(holder);
this.mPendingRemovals.add(holder);
return true;
}
当条目状态改变时
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
return this.animateMove(oldHolder, fromX, fromY, toX, toY);
} else {
float prevTranslationX = oldHolder.itemView.getTranslationX();
float prevTranslationY = oldHolder.itemView.getTranslationY();
float prevAlpha = oldHolder.itemView.getAlpha();
this.resetAnimation(oldHolder);
int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
this.resetAnimation(newHolder);
newHolder.itemView.setTranslationX((float)(-deltaX));
newHolder.itemView.setTranslationY((float)(-deltaY));
newHolder.itemView.setAlpha(0.0F);
}
this.mPendingChanges.add(new DefaultItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
}
以上四个方法并不是为了执行动画,而是初始化动画的准备工作,它们的作用大致有两个:
【一】
设置ViewHolder的初始状态,比如:
newHolder.itemView.setAlpha(0.0F);
【二】
存储将要执行动画的ViewHolder,比如:
//存储将要执行动画的ViewHolder(移除Item)
this.mPendingRemovals.add(holder);
//存储将要执行动画的ViewHolder(Item状态改变)
this.mPendingChanges.add(new DefaultItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
//存储将要执行动画的ViewHolder(位移Item)
this.mPendingMoves.add(new DefaultItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
//存储将要执行动画的ViewHolder(新增Item)
this.mPendingAdditions.add(holder);
当一切准备工作做好之后,开始执行runPendingAnimations
方法
public void runPendingAnimations() {
boolean removalsPending = !this.mPendingRemovals.isEmpty();
boolean movesPending = !this.mPendingMoves.isEmpty();
boolean changesPending = !this.mPendingChanges.isEmpty();
boolean additionsPending = !this.mPendingAdditions.isEmpty();
if (removalsPending || movesPending || additionsPending || changesPending) {
Iterator var5 = this.mPendingRemovals.iterator();
while(var5.hasNext()) {
ViewHolder holder = (ViewHolder)var5.next();
this.animateRemoveImpl(holder);
}
this.mPendingRemovals.clear();
final ArrayList additions;
Runnable adder;
if (movesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingMoves);
this.mMovesList.add(additions);
this.mPendingMoves.clear();
adder = new Runnable() {
public void run() {
Iterator var1 = additions.iterator();
while(var1.hasNext()) {
DefaultItemAnimator.MoveInfo moveInfo = (DefaultItemAnimator.MoveInfo)var1.next();
DefaultItemAnimator.this.animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
}
additions.clear();
DefaultItemAnimator.this.mMovesList.remove(additions);
}
};
if (removalsPending) {
View view = ((DefaultItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (changesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingChanges);
this.mChangesList.add(additions);
this.mPendingChanges.clear();
adder = new Runnable() {
public void run() {
Iterator var1 = additions.iterator();
while(var1.hasNext()) {
DefaultItemAnimator.ChangeInfo change = (DefaultItemAnimator.ChangeInfo)var1.next();
DefaultItemAnimator.this.animateChangeImpl(change);
}
additions.clear();
DefaultItemAnimator.this.mChangesList.remove(additions);
}
};
if (removalsPending) {
ViewHolder holder = ((DefaultItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (additionsPending) {
additions = new ArrayList();
additions.addAll(this.mPendingAdditions);
this.mAdditionsList.add(additions);
this.mPendingAdditions.clear();
adder = new Runnable() {
public void run() {
Iterator var1 = additions.iterator();
while(var1.hasNext()) {
ViewHolder holder = (ViewHolder)var1.next();
DefaultItemAnimator.this.animateAddImpl(holder);
}
additions.clear();
DefaultItemAnimator.this.mAdditionsList.remove(additions);
}
};
if (!removalsPending && !movesPending && !changesPending) {
adder.run();
} else {
long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
long moveDuration = movesPending ? this.getMoveDuration() : 0L;
long changeDuration = changesPending ? this.getChangeDuration() : 0L;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = ((ViewHolder)additions.get(0)).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
}
}
}
}
runPendingAnimations
方法中,有执行四种动画的方法,分别是:
【animateRemoveImpl】
删除动画
【animateChangeImpl】
状态改变动画
【animateAddImpl】
添加条目动画
【animateMoveImpl】
条目位移动画
所以,可以断定,runPendingAnimations
方法的作用是执行所有集合中的动画。
RecyclerView条目动画执行流程
从源码分析,RecyclerView条目动画执行过程是:(很重要)
animateAdd-->runPendingAnimations-->animateAddImpl
animateMove-->runPendingAnimations-->animateMoveImpl
animateRemove-->runPendingAnimations-->animateRemoveImpl
animateChange-->runPendingAnimations-->animateChangeImpl
前面源码看不懂不要紧,但是条目动画基本执行流程必须要清楚,因为接下来开始一步一步的手写自定义DefaultItemAnimator。
【第一步】
新建DefaultItemAnimator类,继承DefaultItemAnimator
我们看一下DefaultItemAnimator类,它的回调方法都是从父类DefaultItemAnimator重写过来的
public class MyCustomItemAnimator extends DefaultItemAnimator {
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) {
return super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
@Override
public void runPendingAnimations() {
super.runPendingAnimations();
}
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
return super.animateRemove(holder);
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
return super.animateAdd(holder);
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
return super.animateMove(holder, fromX, fromY, toX, toY);
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
super.endAnimation(item);
}
@Override
public boolean isRunning() {
return super.isRunning();
}
@Override
public void endAnimations() {
super.endAnimations();
}
}
那些方法有什么用呢?(重点)
- canReuseUpdatedViewHolder
RecyclerView的复用机制是否可用,这里一般默认即可,或者将这个返回值改成true,也就是说,默认复用机制可用。然而,决定RecyclerView是否可以复用不仅仅是根据canReuseUpdatedViewHolder方法的返回值,而且还需要看Adapter中的getItemViewType方法的返回值。
也就是说,当canReuseUpdatedViewHolder的返回值为true并且多个ViewHolder为同一个类型,说明可复用。
@Override
public int getItemViewType(int position) {
//所有ViewHolder类型都是0,所有都可复用
return 0;
}
@Override
public int getItemViewType(int position) {
//所有ViewHolder类型都是不一样,所有都不可复用
return position;
}
@Override
public int getItemViewType(int position) {
//ViewHolder类型为0的可以相互复用,ViewHolder类型为1的可以相互复用,不同类型的不可相互复用
if(a){
return 0;
}else{
return 1;
}
}
- animateAdd
这个方法的作用是存储即将被添加的ViewHolder。
这个方法的执行是最为频繁的了。
当RecyclerView删除某一项时,删除项之后的项都要被重新添加;
当RecyclerView新增某项时,新增项之后的项都要被重新添加;
当RecyclerView指定两个项相互对换位移时,这两项需要被重新添加;
- animateRemove
这个方法的作用是存储即将被删除的ViewHolder。
当删除某项时,会执行这个方法。
- animateMove
这个方法的作用是存储即将被位移的ViewHolder。
当新增项、删除项、项状态改变时都会执行到这个回调。
需要说明的是,当交换某两项位置时,这里只会触发animateAdd方法,而不会执行animateMove方法。
- animateChange
这个方法的作用是存储即将状态被改变的ViewHolder。
当项状态改变时,执行animateChange方法。
- isRunning
判断当前动画是否正在执行。
- runPendingAnimations
这个方法才是最终执行动画的地方,animateAdd、animateRemove、animateMove、animateChange这四个方法只是将将要执行动画的ViewHolder保存到集合里面,最终这四个集合会在runPendingAnimations方法里遍历,将所有的ViewHolder执行动画。
- endAnimation
结束动画时调用。
- endAnimations
结束动画时调用。
【第二步】
条目被添加、删除、位移、改变时会执行到哪些方法?
- 添加项
adapter.notifyItemInserted(position);
当在指定位置插入某项时,会执行animateMove和animateAdd方法存储ViewHolder,最后执行runPendingAnimations方法执行动画。
- 删除项
adapter.notifyItemRemoved(position);
当删除某项时,会执行animateRemove、animateAdd、animateMove这三个方法存储ViewHolder,最后执行runPendingAnimations方法执行动画。
- 位移项
adapter.notifyItemMoved(position, position + 1);
当两个项互相交换位置时,执行animateAdd方法存储ViewHolder,最后执行runPendingAnimations方法执行动画。
- 项状态改变
adapter.notifyItemChanged(position);
当项状态改变时,执行animateChange和animateMove方法存储ViewHolder,最后执行runPendingAnimations方法执行动画。
【第三步】
将DefaultItemAnimator类中的基本实现拷贝到MyCustomItemAnimator方法中,报错的地方可以自行修改。
以下贴出我整理之后的代码
public class MyCustomItemAnimator extends DefaultItemAnimator {
//用于存储将要移动的MoveInfo对象
private ArrayList<MyCustomItemAnimator.MoveInfo> mPendingMoves = new ArrayList();
//MoveInfo的临时存储集合
private ArrayList<ArrayList<MyCustomItemAnimator.MoveInfo>> mMovesList = new ArrayList();
//用于存储正在执行移动动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList();
//用于存储将要被添加的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList();
//存储被添加的ViewHolder的临时集合
private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList();
//用于存储正在执行添加动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList();
//用于存储将要删除的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList();
//用于存储正在执行删除动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList();
//用于存储将要改变的ViewHolder
private ArrayList<MyCustomItemAnimator.ChangeInfo> mPendingChanges = new ArrayList();
//存储被改变的ViewHolder的临时集合
private ArrayList<ArrayList<MyCustomItemAnimator.ChangeInfo>> mChangesList = new ArrayList();
//用于存储正在执行改变动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList();
//定义一个插值器:先向相反方向改变,再加速播放,会超出目标值
private AnticipateOvershootInterpolator accelerateDecelerateInterpolator;
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
return true;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
//添加条目动画实现
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
//让被添加的条目初始完全透明
holder.itemView.setAlpha(0.0f);
//把即将被添加的ViewHolder暂时缓存到mPendingAdditions中
mPendingAdditions.add(holder);
return true;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
//移动条目动画实现
View view = holder.itemView;
fromX += (int)holder.itemView.getTranslationX();
fromY += (int)holder.itemView.getTranslationY();
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
} else {
if (deltaX != 0) {
view.setTranslationX((float)(-deltaX));
}
if (deltaY != 0) {
view.setTranslationY((float)(-deltaY));
}
mPendingMoves.add(new MyCustomItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
}
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
//删除条目动画实现
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
//把将要执行删除动画的ViewHolder放入mPendingRemovals集合
mPendingRemovals.add(holder);
return true;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
//改变条目动画实现
if (oldHolder == newHolder) {
return this.animateMove(oldHolder, fromX, fromY, toX, toY);
} else {
float prevTranslationX = oldHolder.itemView.getTranslationX();
float prevTranslationY = oldHolder.itemView.getTranslationY();
float prevAlpha = oldHolder.itemView.getAlpha();
//开始重置动画
oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(oldHolder);
int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
//开始重置动画
newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(newHolder);
newHolder.itemView.setTranslationX((float)(-deltaX));
newHolder.itemView.setTranslationY((float)(-deltaY));
newHolder.itemView.setAlpha(0.0F);
}
this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (removalsPending || movesPending || additionsPending || changesPending) {
Iterator var5 = mPendingRemovals.iterator();
while(var5.hasNext()) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var5.next();
this.animateRemoveImpl(holder);
}
mPendingRemovals.clear();
ArrayList additions;
Runnable adder;
if (movesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingMoves);
this.mMovesList.add(additions);
this.mPendingMoves.clear();
final ArrayList finalAdditions2 = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions2.iterator();
while(var1.hasNext()) {
MyCustomItemAnimator.MoveInfo moveInfo = (MyCustomItemAnimator.MoveInfo)var1.next();
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
}
finalAdditions2.clear();
mMovesList.remove(finalAdditions2);
}
};
if (removalsPending) {
View view = ((MyCustomItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (changesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingChanges);
mChangesList.add(additions);
this.mPendingChanges.clear();
final ArrayList finalAdditions1 = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions1.iterator();
while(var1.hasNext()) {
MyCustomItemAnimator.ChangeInfo change = (MyCustomItemAnimator.ChangeInfo)var1.next();
animateChangeImpl(change);
}
finalAdditions1.clear();
mChangesList.remove(finalAdditions1);
}
};
if (removalsPending) {
RecyclerView.ViewHolder holder = ((MyCustomItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (additionsPending) {
additions = new ArrayList();
additions.addAll(this.mPendingAdditions);
this.mAdditionsList.add(additions);
this.mPendingAdditions.clear();
final ArrayList finalAdditions = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions.iterator();
while(var1.hasNext()) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var1.next();
animateAddImpl(holder);
}
finalAdditions.clear();
mAdditionsList.remove(finalAdditions);
}
};
if (!removalsPending && !movesPending && !changesPending) {
adder.run();
} else {
long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
long moveDuration = movesPending ? this.getMoveDuration() : 0L;
long changeDuration = changesPending ? this.getChangeDuration() : 0L;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = ((RecyclerView.ViewHolder)additions.get(0)).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
}
}
}
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
super.endAnimation(item);
}
@Override
public boolean isRunning() {
//用于判断动画是否正在执行
return super.isRunning();
}
@Override
public void endAnimations() {
super.endAnimations();
}
/**
* Item状态改变时的动画
* @param changeInfo
*/
void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
ViewPropertyAnimator newViewAnimation;
if (view != null) {
newViewAnimation = view.animate().setDuration(this.getChangeDuration());
mChangeAnimations.add(changeInfo.oldHolder);
newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
view.setAlpha(1.0F);
view.setTranslationX(0.0F);
view.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
if (newView != null) {
newViewAnimation = newView.animate();
this.mChangeAnimations.add(changeInfo.newHolder);
final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
newViewAnimation.translationX(0.0F).translationY(0.0F).setDuration(this.getChangeDuration()).alpha(1.0F).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
newView.setAlpha(1.0F);
newView.setTranslationX(0.0F);
newView.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
}
/**
* Item移动实现
* @param holder
* @param fromX
* @param fromY
* @param toX
* @param toY
*/
void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
view.animate().translationX(0.0F);
}
if (deltaY != 0) {
view.animate().translationY(0.0F);
}
final ViewPropertyAnimator animation = view.animate();
this.mMoveAnimations.add(holder);
animation.setDuration(this.getMoveDuration()).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchMoveStarting(holder);
}
public void onAnimationCancel(Animator animator) {
if (deltaX != 0) {
view.setTranslationX(0.0F);
}
if (deltaY != 0) {
view.setTranslationY(0.0F);
}
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
/**
* 添加Item动画实现
* @param holder
*/
void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mAddAnimations.add(holder);
animation.alpha(1.0F).setDuration(this.getAddDuration()).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
public void onAnimationCancel(Animator animator) {
view.setAlpha(1.0F);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
/**
* 移除Item动画实现
* @param holder
*/
private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mRemoveAnimations.add(holder);
animation.setDuration(this.getRemoveDuration()).alpha(0.0F).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
view.setAlpha(1.0F);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
private static class MoveInfo {
public RecyclerView.ViewHolder holder;
public int fromX;
public int fromY;
public int toX;
public int toY;
MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
private static class ChangeInfo {
public RecyclerView.ViewHolder oldHolder;
public RecyclerView.ViewHolder newHolder;
public int fromX;
public int fromY;
public int toX;
public int toY;
private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
public String toString() {
return "ChangeInfo{oldHolder=" + this.oldHolder + ", newHolder=" + this.newHolder + ", fromX=" + this.fromX + ", fromY=" + this.fromY + ", toX=" + this.toX + ", toY=" + this.toY + '}';
}
}
}
以上代码算是照搬DefaultItemAnimator源码,接下来回基于已整理好的代码上修改动画。
【第四步】
修改添加条目动画
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
//添加条目动画实现
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
//让被添加的条目初始完全透明
holder.itemView.setAlpha(0.0f);
//把即将被添加的ViewHolder暂时缓存到mPendingAdditions中
mPendingAdditions.add(holder);
return true;
}
这个方法的执行比较频繁,这里保持默认,先重置动画,再将Item完全透明,最后将ViewHolder添加到mPendingAdditions集合中。
/**
* 添加Item动画实现
* @param holder
*/
void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mAddAnimations.add(holder);
animation.alpha(1.0F).setDuration(2000).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
public void onAnimationCancel(Animator animator) {
view.setAlpha(1.0F);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
animateAddImpl方法基本也没有变化,只是将动画时长改成2000ms。
当ViewHolder不可复用时,它的执行效果如下:
当ViewHolder可复用时,它的执行效果如下:
【第五步】
修改位移动画
位移动画本身就写的挺不错了,这里偷个懒就只将动画时间修改为1秒。
位移动画主要体现在新增条目和删除条目上。
效果如下:(由于添加动画被完全透明了,所以这里只展示ViewHolder被复用的情况)
【第六步】
修改删除动画
修改之后的代码如下:
/**
* 移除Item动画实现
* @param holder
*/
private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mRemoveAnimations.add(holder);
animation.setDuration(1000)
.translationX(holder.itemView.getWidth())
.setInterpolator(new AnticipateOvershootInterpolator())
.setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
view.setTranslationX(0);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
ViewHolder不可被复用的效果如下:
ViewHolder可被复用的效果如下:
【第七步】
修改状态改变时的动画
修改后的代码如下:
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
//改变条目动画实现
float prevTranslationX = oldHolder.itemView.getTranslationX();
float prevTranslationY = oldHolder.itemView.getTranslationY();
float prevAlpha = oldHolder.itemView.getAlpha();
//开始重置动画
oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(oldHolder);
int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
//开始重置动画
newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(newHolder);
newHolder.itemView.setTranslationX((float)(-deltaX));
newHolder.itemView.setTranslationY((float)(-deltaY));
newHolder.itemView.setAlpha(0.0F);
}
this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
在初始化的时候,oldHolder的透明度保持不变,newHolder给它完全透明。
/**
* Item状态改变时的动画
* @param changeInfo
*/
void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
ViewPropertyAnimator newViewAnimation;
if (view != null) {
newViewAnimation = view.animate().setDuration(2000);
mChangeAnimations.add(changeInfo.oldHolder);
newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
view.setAlpha(1.0F);
view.setTranslationX(0.0F);
view.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
if (newView != null) {
newViewAnimation = newView.animate();
this.mChangeAnimations.add(changeInfo.newHolder);
final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
newViewAnimation
.setDuration(2000)
.alpha(1.0F)
.setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
newView.setAlpha(1.0F);
newView.setTranslationX(0.0F);
newView.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
oldHolder透明度从1到0的动画,newHolder透明度从0到1的动画,动画时长为2000ms,效果如下:
最后,贴出MyCustomItemAnimator类的全部代码
public class MyCustomItemAnimator extends DefaultItemAnimator {
//用于存储将要移动的MoveInfo对象
private ArrayList<MyCustomItemAnimator.MoveInfo> mPendingMoves = new ArrayList();
//MoveInfo的临时存储集合
private ArrayList<ArrayList<MyCustomItemAnimator.MoveInfo>> mMovesList = new ArrayList();
//用于存储正在执行移动动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList();
//用于存储将要被添加的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList();
//存储被添加的ViewHolder的临时集合
private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList();
//用于存储正在执行添加动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList();
//用于存储将要删除的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList();
//用于存储正在执行删除动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList();
//用于存储将要改变的ViewHolder
private ArrayList<MyCustomItemAnimator.ChangeInfo> mPendingChanges = new ArrayList();
//存储被改变的ViewHolder的临时集合
private ArrayList<ArrayList<MyCustomItemAnimator.ChangeInfo>> mChangesList = new ArrayList();
//用于存储正在执行改变动画的ViewHolder
private ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList();
//定义一个插值器:先向相反方向改变,再加速播放,会超出目标值
private AnticipateOvershootInterpolator accelerateDecelerateInterpolator;
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
return true;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
//添加条目动画实现
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
//让被添加的条目初始完全透明
holder.itemView.setAlpha(0.0f);
//把即将被添加的ViewHolder暂时缓存到mPendingAdditions中
mPendingAdditions.add(holder);
return true;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
//移动条目动画实现
View view = holder.itemView;
fromX += (int)holder.itemView.getTranslationX();
fromY += (int)holder.itemView.getTranslationY();
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
} else {
if (deltaX != 0) {
view.setTranslationX((float)(-deltaX));
}
if (deltaY != 0) {
view.setTranslationY((float)(-deltaY));
}
mPendingMoves.add(new MyCustomItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
}
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
//删除条目动画实现
//开始重置动画
holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(holder);
//把将要执行删除动画的ViewHolder放入mPendingRemovals集合
mPendingRemovals.add(holder);
return true;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
//改变条目动画实现
float prevTranslationX = oldHolder.itemView.getTranslationX();
float prevTranslationY = oldHolder.itemView.getTranslationY();
float prevAlpha = oldHolder.itemView.getAlpha();
//开始重置动画
oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(oldHolder);
int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
//开始重置动画
newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
endAnimation(newHolder);
newHolder.itemView.setTranslationX((float)(-deltaX));
newHolder.itemView.setTranslationY((float)(-deltaY));
newHolder.itemView.setAlpha(0.0F);
}
this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (removalsPending || movesPending || additionsPending || changesPending) {
Iterator var5 = mPendingRemovals.iterator();
while(var5.hasNext()) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var5.next();
this.animateRemoveImpl(holder);
}
mPendingRemovals.clear();
ArrayList additions;
Runnable adder;
if (movesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingMoves);
this.mMovesList.add(additions);
this.mPendingMoves.clear();
final ArrayList finalAdditions2 = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions2.iterator();
while(var1.hasNext()) {
MyCustomItemAnimator.MoveInfo moveInfo = (MyCustomItemAnimator.MoveInfo)var1.next();
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
}
finalAdditions2.clear();
mMovesList.remove(finalAdditions2);
}
};
if (removalsPending) {
View view = ((MyCustomItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (changesPending) {
additions = new ArrayList();
additions.addAll(this.mPendingChanges);
mChangesList.add(additions);
this.mPendingChanges.clear();
final ArrayList finalAdditions1 = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions1.iterator();
while(var1.hasNext()) {
MyCustomItemAnimator.ChangeInfo change = (MyCustomItemAnimator.ChangeInfo)var1.next();
animateChangeImpl(change);
}
finalAdditions1.clear();
mChangesList.remove(finalAdditions1);
}
};
if (removalsPending) {
RecyclerView.ViewHolder holder = ((MyCustomItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
} else {
adder.run();
}
}
if (additionsPending) {
additions = new ArrayList();
additions.addAll(this.mPendingAdditions);
this.mAdditionsList.add(additions);
this.mPendingAdditions.clear();
final ArrayList finalAdditions = additions;
adder = new Runnable() {
public void run() {
Iterator var1 = finalAdditions.iterator();
while(var1.hasNext()) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var1.next();
animateAddImpl(holder);
}
finalAdditions.clear();
mAdditionsList.remove(finalAdditions);
}
};
if (!removalsPending && !movesPending && !changesPending) {
adder.run();
} else {
long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
long moveDuration = movesPending ? this.getMoveDuration() : 0L;
long changeDuration = changesPending ? this.getChangeDuration() : 0L;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = ((RecyclerView.ViewHolder)additions.get(0)).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
}
}
}
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
super.endAnimation(item);
}
@Override
public boolean isRunning() {
//用于判断动画是否正在执行
return super.isRunning();
}
@Override
public void endAnimations() {
super.endAnimations();
}
/**
* Item状态改变时的动画
* @param changeInfo
*/
void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
ViewPropertyAnimator newViewAnimation;
if (view != null) {
newViewAnimation = view.animate().setDuration(2000);
mChangeAnimations.add(changeInfo.oldHolder);
newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
view.setAlpha(1.0F);
view.setTranslationX(0.0F);
view.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
if (newView != null) {
newViewAnimation = newView.animate();
this.mChangeAnimations.add(changeInfo.newHolder);
final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
newViewAnimation
.setDuration(2000)
.alpha(1.0F)
.setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
public void onAnimationEnd(Animator animator) {
finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
newView.setAlpha(1.0F);
newView.setTranslationX(0.0F);
newView.setTranslationY(0.0F);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
}
/**
* Item移动实现
* @param holder
* @param fromX
* @param fromY
* @param toX
* @param toY
*/
void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
view.animate().translationX(0.0F);
}
if (deltaY != 0) {
view.animate().translationY(0.0F);
}
final ViewPropertyAnimator animation = view.animate();
this.mMoveAnimations.add(holder);
animation.setDuration(1000).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchMoveStarting(holder);
}
public void onAnimationCancel(Animator animator) {
if (deltaX != 0) {
view.setTranslationX(0.0F);
}
if (deltaY != 0) {
view.setTranslationY(0.0F);
}
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
/**
* 添加Item动画实现
* @param holder
*/
void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mAddAnimations.add(holder);
animation.alpha(1.0F).setDuration(2000).setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
public void onAnimationCancel(Animator animator) {
view.setAlpha(1.0F);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
/**
* 移除Item动画实现
* @param holder
*/
private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
this.mRemoveAnimations.add(holder);
animation.setDuration(1000)
.translationX(holder.itemView.getWidth())
.setInterpolator(new AnticipateOvershootInterpolator())
.setListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
public void onAnimationEnd(Animator animator) {
animation.setListener((Animator.AnimatorListener)null);
view.setTranslationX(0);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
}).start();
}
private static class MoveInfo {
public RecyclerView.ViewHolder holder;
public int fromX;
public int fromY;
public int toX;
public int toY;
MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
private static class ChangeInfo {
public RecyclerView.ViewHolder oldHolder;
public RecyclerView.ViewHolder newHolder;
public int fromX;
public int fromY;
public int toX;
public int toY;
private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
public String toString() {
return "ChangeInfo{oldHolder=" + this.oldHolder + ", newHolder=" + this.newHolder + ", fromX=" + this.fromX + ", fromY=" + this.fromY + ", toX=" + this.toX + ", toY=" + this.toY + '}';
}
}
}
[本章完...]