1.RecyclerView动画原理
这几天熟悉了RecyclerView的使用以及内部动画机制,有几篇文章做备忘:
2.RecyclerView首次加载动画
RecyclerView本身对添加动画和删除动画支持的很好,但首次加载自定义起来并不容易。目前看来主流的方法:
- 1.在Adapter的 public void onBindViewHolder(T holder, int position)方法中根据bool变量或者mLastpostion判断是否首次加载。
- 2.第二种是根据Stack Overflow上面的解答,在RecyclerView即将绘制的时候做相关操作,当然跟新视图数据也会调用该方法,需要加些条件判断
private void firstLoadAnimation(){
//首次加载这种比较有效
mRecylerView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mRecylerView.getViewTreeObserver().removeOnPreDrawListener(this);
final int screenWidth = MyUtils.getScreenWidth(MainActivity.this);
for (int i = 0; i < mRecylerView.getChildCount(); i++) {
View v = mRecylerView.getChildAt(i);
v.setTranslationX(screenWidth);
v.animate().translationX(0)
.setDuration(1000)
.setStartDelay(i * 50)
.start();
}
return true;
}
});
}
- 3.第三种是在recyclerView首次已经加载(为空数据,在上面demo5上是动画结束后),然后适当延迟可以调用。首先继承DefaultItemAnimator,然后修改public boolean animateAdd(RecyclerView.ViewHolder viewHolder)方法,示例如下代码
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
if (holder.getAdapterPosition() > lastAddAnimatedItem){
lastAddAnimatedItem++;
runEnterAnimator((MyAdapter.ViewHolder)holder);
return false;
}
dispatchAddFinished(holder);
return false;
}
private void runEnterAnimator(final MyAdapter.ViewHolder holder){
final int screenWidth = MyUtils.getScreenWidth(holder.itemView.getContext());
holder.itemView.setTranslationX(screenWidth);
int delayTimes = Math.max(10*lastAddAnimatedItem,0);
holder.itemView.animate()
.translationX(0)
.setInterpolator(new DecelerateInterpolator(3.f))
.setDuration(2000)
.setStartDelay(delayTimes)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
dispatchAddFinished(holder);
}
}
)
.start();
}
当Adapter触发 notifyItemRangeInserted()或者notifyItemInserted()的时候, 这个 RecyclerView.ItemAnimator的animateAdd方法将被调用。
- 4.还有一种就是利用LayoutAniamtionController,可参考如下代码:
private void runLayoutAnimation(final RecyclerView recyclerView, final AnimationItem item) {
final Context context = recyclerView.getContext();
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(context, item.getResourceId());
recyclerView.setLayoutAnimation(controller);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.scheduleLayoutAnimation();
}
其中AnimationItem对应的是对话对应的资源文件,比如从右侧延迟滑动滚入的动画xml,对应的item动画如下:
item_animation_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/anim_duration_long">
<translate
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="100%p"
android:toXDelta="0"
/>
<alpha
android:fromAlpha="0.5"
android:toAlpha="1"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
/>
</set>
layoutAnimation如下:
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
android:animation="@anim/item_animation_from_right"
xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="20%"
android:animationOrder="normal">
</layoutAnimation>
第四种方法参考文章Enter animation using RecyclerView and LayoutAnimation Part 1: Lists
个人觉得四中方法还是最后一种方法简单方便。