首先 RecycleView是有一套自己默认的动画、以及相应执行时机
但是在项目开发中,遇到了需要为删除item的动效进行调整
思路1. 可以在holder中(比如点删除的点击事件)直接为当前view设置自定义动画并执行
思路2. 重写recycleView默认动画 SimpleItemAnimator
简单的场景下思路1是可以达到预期效果的,但是个人在项目中遇到了另一个难题,ui给的动画需要在执行删除动画的同时 下方列表要同时上移。
但是recycleView默认的是删除动画执行完之后才去执行移动动画 这种情况下思路1就无法达到预期 只能重写SimpleItemAnimator了
好消息是recycleView自身已经封装好了一个默认DefaultItemAnimator该类中对抽象类SimpleItemAnimator所有方法都以重写实现 我们只要继承DefaultItemAnimator对需要调整的方法重写即可
坏消息是 内部没有能直接提供调用开始移动动画或删除动画的方法 有的是runPendingAnimations() 该方法内部设置了各个动画的执行时机,我们重写这个方法 几乎等同于需要重写整个类
源码如下
@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) {
return;
}
// 执行Remove动画
for (RecyclerView.ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder); // 实际执行Remove动画的方法
}
mPendingRemovals.clear();
// Move动画
if (movesPending) {
// 注意: Move动画并不是马上执行,会放入一个Runnable
Runnable mover = new Runnable() {
@Override
public void run() {
for (MoveInfo moveInfo : moves) {
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
moveInfo.toX, moveInfo.toY);
}
}
};
// 如果有Remove动画,就在Remove动画结束之后执行Move动画
// 如果没有Remove动画就马上执行
if (removalsPending) {
View view = moves.get(0).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
} else {
mover.run();
}
}
// Change动画,与Move动画一起执行
if (changesPending) {
// ......
Runnable changer = new Runnable() {
@Override
public void run() {
for (ChangeInfo change : changes) {
animateChangeImpl(change);
}
}
};
if (removalsPending) {
RecyclerView.ViewHolder holder = changes.get(0).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
} else {
changer.run();
}
}
// 最后执行Add动画
if (additionsPending) {
// ......
Runnable adder = new Runnable() {
@Override
public void run() {
for (RecyclerView.ViewHolder holder : additions) {
animateAddImpl(holder);
}
additions.clear();
mAdditionsList.remove(additions);
}
};
// 在Remove、Move、Change动画都完成之后开始执行Add动画
if (removalsPending || movesPending || changesPending) {
long removeDuration = removalsPending ? getRemoveDuration() : 0;
long moveDuration = movesPending ? getMoveDuration() : 0;
long changeDuration = changesPending ? getChangeDuration() : 0;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = additions.get(0).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
} else {
adder.run();
}
}
}
通过源码可以发现 我们要达到目标 只需要将 mover.run();执行的判断条件去掉即可 但是却要为此重写大量内容。
而从写删除数据的animateRemove()方法就要简便许多:
只需要为holder内的itemview增加动画即可
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
Animation animation = null;
// 增加item消失动画
switch (itemId) {
case R.id.rv_list:
animation = AnimationUtils.loadAnimation(holder.itemView.getContext(), R.anim.move_animation);
holder.itemView.setAnimation(animation);
break;
case R.id.rv_list_v2:
animation = AnimationUtils.loadAnimation(holder.itemView.getContext(), R.anim.move_animation_v2);
holder.itemView.setAnimation(animation);
break;
default:
break;
}
// 原父类方法内容
resetAnimation(holder);
mPendingRemovals.add(holder);
return true;
}
最后则是外部设置:
recycleView.setItemAnimator(new RecycleAnimation());
// 设置删除动画执行时长 单位ms
recycleView.getItemAnimator().setRemoveDuration(333);
本文介绍了在项目开发中如何自定义RecyclerView的删除和移动动画。针对UI的特定需求,提出了两种思路:直接在ViewHolder中设置动画或重写RecycleView的SimpleItemAnimator。在遇到需要同步执行删除和移动动画的场景时,由于RecyclerView默认行为的限制,选择重写SimpleItemAnimator的animateRemove()方法来实现预期效果。文章还分享了源码分析和简化重写过程的技巧。
474

被折叠的 条评论
为什么被折叠?



