给滚动列表项增加渐显载入动画

之前还在使用ListView作为展示列表数据的控件时尝试过给列表项增加载入动画,但是ListView是一个效果比较单一的控件,
在想要实现表格布局或者是瀑布流的载入动画的时候还要分别给GridView和瀑布流控件分别实现,这是比较麻烦的。
在之前的博客中提到过RecyclerView这个控件,这是在V7包中提供的一个功能非常强大而且扩展性非常强的一个控件,
用它可以实现列表、表格、瀑布流等效果,只需要指定不同的LayoutManager即可,具体的用法在之前的博客中已经记录过,
在这里就不再赘述。
今天记录的是给RecyclerView增加item的载入动画,这样在借助RecyclerView的特性下在不同效果的布局模式中就可以显示相同的效果,
而不用分别进行实现,下面是效果:
列表动画 grid动画 瀑布流动画

依照惯例,我们定义一个带有RecyclerView的Activity,然后放一些测试数据进去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// recyclerView.setLayoutManager(new GridLayoutManager(this ,3));
// recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL));
TestAnimAdapter testAnimAdapter = new TestAnimAdapter();
recyclerView.setAdapter(testAnimAdapter);
}
}

然后是Adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class TestAnimAdapter extends RecyclerView.Adapter<TestAnimAdapter.MyViewHolder> {
int lastPosition = -1;
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item, parent, false);
return new MyViewHolder(inflate);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_title.setText("测试" + position);
}
@Override
public int getItemCount() {
return 1000;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_title;
public MyViewHolder(View itemView) {
super(itemView);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
}
}
}

现在用RecyclerView实现的简单的带有1000条测试数据的列表UI构建完毕,接下来就是如何添加动画了。
RecyclerView在item即将进入可视区域时会调用onBindViewHolder方法,传入被recycle的holder进行初始化数据,
那么我们就可以在这里下手,在item初始化数据的时候指定一个动画,来让item进入用户视野的时候伴随着动画的执行。
下面以一个渐现动画为例:

1
2
3
4
5
6
7
8
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_title.setText("测试" + position);
int adapterPosition = holder.getAdapterPosition();
Animator animator = ObjectAnimator.ofFloat(holder.itemView, "alpha", 0, 1f);
animator.setDuration(1000).start();
}

上面这段为item进入视野时增加了一个渐现的动画,而实际运行的时候好像和我们的预期有一些偏差
和预期有偏差的动画效果
我们发现在列表上拉的时候也会有一个动画效果,而这并不是我们想要的,这需要怎么处理呢?
我们需要动画在一个item只会在首次进入视野的时候执行动画,而不是每次都执行。
holder的position代表这item的位置,我们存储一个代表当前加载到的最大位置的变量,如果加载到的item的position大于这个变量,则是首次加载。
接下来改造代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int lastPosition = -1;
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_title.setText("测试" + position);
int adapterPosition = holder.getAdapterPosition();
if (adapterPosition > lastPosition) {
Animator animator = ObjectAnimator.ofFloat(holder.itemView, "alpha", 0, 1f);
animator.setDuration(1000).start();
lastPosition = adapterPosition;
} else {
ViewCompat.setAlpha(holder.itemView, 1);
}
}

OK,搞定!
这时候再执行我们的代码就可以实现开篇上面的动画了,至于Grid和瀑布流(StaggeredGrid)的样式我们并不需要单独实现,只要更改RecyclerView的LayoutManager即可:

1
2
3
// recyclerView.setLayoutManager(new LinearLayoutManager(this));//列表
recyclerView.setLayoutManager(new GridLayoutManager(this ,3));//3列gird
// recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL));//3列瀑布流

文章目录
,