「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
一、 分割线
RecyclerView分割线有两种:
- 默认分割线
- 自定义分割线
1. 默认分割线
DividerItemDecoration是RecyclerView默认分割线,只需要new一个DividerItemDecoration,调用RecyclerView的addItemDecoration()即可 具体是实现:
DividerItemDecoration dividerItemDecoration=new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(dividerItemDecoration);
2. 自定义分割线
自定义分割线有很多种实现方式,我们介绍2种
- 调用setDrawable 这种和上面很像,不同的是,我们需要在drawable定义一个属性或者存放一张图片,在调用DividerItemDecoration的setDrawable方法将它取出来
DividerItemDecoration dividerItemDecoration=new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.shape_divider));
recyclerView.addItemDecoration(dividerItemDecoration);
- 继承RecyclerView.ItemDecoration 继承成RecyclerView.ItemDecoration
在RecyclerView.ItemDecoration里面有3个方法
(1) getItemOffsets() 可以调用outRect.set()设置每个Item的padding
(2) onDraw() 可以在绘制item之前绘制我们需要的内容,主要调用Canvas.drawXX()方法来绘制
(3) onDrawOver() 是在绘制item之后调用,是绘制在item上层
二、 动画
实现RecyclerView的动画效果,我们可以用官方推荐的RecyclerView.ItemAnimator,它主要是用于Item的添加、移除、更新
其实系统为我们提供了默认的动画DefaultItemAnimator,所以即使我们不定义,也会有默认的动画效果
我们要自定义RecyclerView.ItemAnimator,可以先了解DefaultItemAnimator,DefaultItemAnimator继承的是抽象类SimpleItemAnimator,所以我们先定义一个DemoItemAnimator继承SimpleItemAnimator,实现其中的方法
- animateRemove() Item移除回调
- animateAdd() Item添加回调
- animateMove() 添加/移动更新时,其他Item的动画
- animateChange() Item更新调用
- runPendingAnimations() 真正执行动画的地方
- endAnimation() 停止某一个Item动画
- endAnimations() 停止所有动画
- isRunning()
再来看看DefaultItemAnimator中的实现
- animateRemove() 里面只有两行代码,第一句是删除要被移除的Item所有动画的相关代码。第二句是往一个List中添加了当前的ViewHolder
@Override
public boolean animateRemove(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
mPendingRemovals.add(holder);
return true;
}
- animateAdd() 初始化Item的动画状态,和animateRemove()动画差不多
@Override
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
holder.itemView.setAlpha(0);
mPendingAdditions.add(holder);
return true;
}
- animateMove() 把目标位置和未执行操作的当前位置差值计算出来,把Item位移到未操作前的位置
方法里面有5个参数,分别是要移动的ViewHolder、起始x,y值、目标x,y值
@Override
public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY,
int toX, int toY) {
. . .
fromX += (int) holder.itemView.getTranslationX();
fromY += (int) holder.itemView.getTranslationY();
resetAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
. . .
mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
- animateChange() 里面有一个判断:如果是同一个ViewHolder则直接调用animatoMove(),否则在内部多记录了一个alpha的值
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
. . .
return animateMove(oldHolder, fromX, fromY, toX, toY);
}
. . .
if (newHolder != null) {
// carry over translation values
resetAnimation(newHolder);
newHolder.itemView.setTranslationX(-deltaX);
newHolder.itemView.setTranslationY(-deltaY);
newHolder.itemView.setAlpha(0);
}
mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
- runPendingAnimations() 首先判断List(Pending)中是否存在待处理动画,如果不存在的话就退出,如果存在就开始依次执行动画
@Override
public void runPendingAnimations() {
. . .
if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
// nothing to animate
return;
}
// First, remove stuff
for (RecyclerView.ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder);
}
. . .
// Next, move stuff
if (movesPending) {
. . .
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
. . .
}
// Next, add stuff
if (additionsPending) {
. . .
}
}
- endAnimation() 取消指定item的动画,然后把List中(待处理/等待运行动画相关数据和正在运行动画的ViewHolder)里面的ViewHolder的都移除掉
- endAnimations() 循环把List里面的ViewHolder都移除掉,然后把调cancelAll()方法把所有正在执行的属性动画停止
- isRunning() 通过判断List是否为空,就会知道是否有动画需要执行或者正在执行
下一篇介绍实现拖拽和侧滑的ItemTounchHelper