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