安卓动画(四)Recyclerview ItemAnimator(下)
程序员文章站
2022-05-05 14:33:35
...
安卓动画(三)Recyclerview ItemAnimator(上)
这一篇就实现下面两种效果:
demo地址:https://github.com/whoami-I/Animation
实现之前,就是要对系统为我们实现的DefaultItemAnimator
这个类进行改造,自己仿照写一个BaseItemAnimator,再在这个类的基础上,自定义我们自己的各种各样的动画,以add动画改造进行举例,DefaultItemAnimator
中关于add动画有两个方法:animateAdd
和animateAddImpl
@Override
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
holder.itemView.setAlpha(0);
mPendingAdditions.add(holder);
return true;
}
animateAdd
方法很简单,其实是add动画之前的一个初始化流程,为了使这个方法更好的扩展,改造成下面的模式:
@Override
public boolean animateAdd(final ViewHolder holder) {
resetAnimation(holder);
addAnimateInit(holder);
mPendingAdditions.add(holder);
return true;
}
addAnimateInit
是一个抽象方法,有待于继承,接下来改造animateAddImpl
方法,DefaultItemAnimator中是这样的
animation.alpha(1).setDuration(getAddDuration())
.setListener(new AnimatorListenerAdapter() {
/*省略*/
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
改造成:
//添加抽象方法
addAnimationStart(holder,animation);
animation.setDuration(getAddDuration()).
setListener(new VpaListenerAdapter() {
/*省略*/
@Override
public void onAnimationEnd(View view) {
animation.setListener(null);
dispatchAddFinished(holder);
/*添加抽象方法*/
addAnimationEnd(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
改造中添加了两个抽象方法,一个是addAnimationStart
在这个方法中要做的是动画最终要变成什么样子;当动画结束,又添加了一个抽象方法,对结束可能需要做一些处理。
上面仅仅是对add动画进行了一个改造,相应的remove也可以最终改造出来,因此最终的BaseItemAnimator里面添加了13个抽象的方法,用于处理各种情况,这样我们以ScaleAnimator举例子来实现其中的一些方法:
@Override
public void removeAnimateInit(RecyclerView.ViewHolder holder) {
//remove初始化,这时itemView的大小应该是正常大小
holder.itemView.setScaleX(1);
holder.itemView.setScaleY(1);
}
@Override
public void removeAnimationStart(RecyclerView.ViewHolder holder, ViewPropertyAnimatorCompat animator) {
//因为要有一个缩小的动画,因此将动画的最终状态设置为scale为0的大小
holder.itemView.setPivotX(holder.itemView.getWidth()/2);
holder.itemView.setPivotY(holder.itemView.getHeight()/2);
animator.scaleX(0).scaleY(0);
}
//当动画结束时,因为此时ViewHolder可能被复用,因此需要将状态设置回来
@Override
public void removeAnimationEnd(RecyclerView.ViewHolder holder) {
holder.itemView.setScaleX(1);
holder.itemView.setScaleY(1);
}
//add动画初始化此时还没添加进来,因此大小为0
@Override
public void addAnimateInit(RecyclerView.ViewHolder holder) {
holder.itemView.setScaleX(0);
holder.itemView.setScaleY(0);
}
//add的最终状态肯定是正常大小
@Override
public void addAnimationStart(RecyclerView.ViewHolder holder, ViewPropertyAnimatorCompat animator) {
ViewCompat.setPivotX(holder.itemView,holder.itemView.getWidth()/2);
ViewCompat.setPivotY(holder.itemView,holder.itemView.getHeight()/2);
animator.scaleX(1).scaleY(1);
}
//最终大小也肯定是1
@Override
public void addAnimationEnd(RecyclerView.ViewHolder holder) {
ViewCompat.setScaleX(holder.itemView,1);
ViewCompat.setScaleY(holder.itemView,1);
}
//因为可能存在一次add还没完,下一次add又开始的情况,因此这时直接就把上一次结果设置成1
@Override
public void addAnimationCancel(RecyclerView.ViewHolder holder) {
ViewCompat.setScaleX(holder.itemView,1);
ViewCompat.setScaleY(holder.itemView,1);
}
好了,这就是scaleAnimator的具体细节,基于这个细节,还能封装Fade、Slide或者各种动画的结合体,具体就看代码吧。
注意:
要实现上面的动画效果,必须是调用notifyItemRemoved
等局部刷新数据相关的API,而不能使用notifyDataSetChanged这种全局性更新数据的API