RecyclerView的灵活多变,让开发者对于android界面的布局有了更多的方式,也因为recyclerView的灵活多变,android越来越有意思。今天先来介绍recyclerView的基本使用。
RecyclerView官方文档
添加依赖
compile 'com.android.support:recyclerview-v7:25.0.0'
这里要注意,recyclerView的版本要与appCompat的版本一致比较好,我记得我之前报错了,忘记记录下来了,不记得是啥了。
布局文件:
很多人都说RecyclerView的出现就是为了替代listview和gridView的,我也不清楚到底是不是这样,但是,listView和Gridview用起来真很简单,所以,在平常的一些地方,能用list view和gridView的,就用他们两,我觉得无可厚非,在这次RecyclerView的基本使用介绍中,我们可以利用recyclerView来实现三种布局,Listview格式的,GridView格式的,瀑布流格式的。
首先,不管是ListView还是GridView还是现在要讲解的RecyclerView,都需要一个适配器。所以,我们先来看看recyclerView的最初的适配器是怎样的吧。
这里先举个栗子
/*最初的适配器是没有viewHolder的,因为要为ItemView设置点击事件,所以这里写了一个ViewHolder继承了
*RecyclerView.ViewHolder,并重写了它的构造方法。
* */
class ListRecyclerViewAdapter extends RecyclerView.Adapter{
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView= (ImageView) itemView.findViewById(R.id.img_recyclerviewItem);
}
}
}
在上面的代码中可以看到,我们的适配器集成了RecyclerView.Adapter并同时继承了他的三个构造方法。仔细观察这三个构造方法可以发现,第一个方法返回的是一个viewHolder对象,第二个方法接受的是一个ViewHolder对象,所以我们可以大胆猜测,第一个方法返回的recyclerView就返回到了第二个方法的形参中,这一点感觉跟AsyncTask的doInBackground与onPostExcute的用法十分的相似。先撇开这个话题不谈,与BaseAdapter类似,在以前我们初始化BaseAdapter的时候,考虑性能优化,也会在自己写一个viewHolder来缓存我们的view,先不急添加点击事件,我们先让我们的itenView给展现出来,所以继续完善我们的Adapter。
class ListRecyclerViewAdapter extends RecyclerView.Adapter{
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView=View.inflate(getApplicationContext(),R.layout.item_recyclerview,null);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.imageView.setImageResource(itemImgs[position]);
}
@Override
public int getItemCount() {
return itemImgs.length;
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView= (ImageView) itemView.findViewById(R.id.img_recyclerviewItem);
}
}
}
与上一步相比较补充的很少,就是在onCreateViewHolder方法中获取我们的itemView,并且将这个itemView封装在viewHolder中返回回去了。然后接下来就是在onBindViewHolder中为我们holder中的数据设置值。onCreateViewHolder和onBindViewHoder在源码中的说明是这样的,recyclerView通过调用它去display指定位置的数据。这个方法应该更新viewHolder中的内容,这个内容是反射位置的条目的内容,翻译有点蹩脚。
/**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the {@link ViewHolder#itemView} to reflect the item at the given
* position.
好了,基本的recyclerView的Adapter指定好了,那么如何使用呢?代码如下。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_list);
//获取控件
recyclerView=(RecyclerView)findViewById(R.id.list_recycler);
//如果设置为真,那么适配器的改变不会影响recyclerView的尺寸,官方文档是这么翻译的
recyclerView.setHasFixedSize(true);
//设置item增加删除的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
//设置线性布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(new ListRecyclerViewAdapter());
}
是的,这样就可以呈现我们要展示的内容了。大家可以注意到,这里调用了三个方法,setHasFixedSize、setItemAnimator、和setLayoutManager。前面两个方法暂且不聊,而第三个方法,就是我们recyclerView实现ListView格式、GridView格式、瀑布流格式的关键,分别对应的是
LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager。
瀑布流的效果如下,有点拉闸。
好了,界面呈现出来了,我们想要像listview和RecyclerView一样为其设置item的点击事件,那么我们就来实现这个功能吧,Adapter是设置点击事件最好的地方
我们修改的adapter代码如下
static class ListRecyclerViewAdapter extends RecyclerView.Adapter
implements View.OnClickListener{
private static int[] mItemsImgs;
public ListRecyclerViewAdapter(int[] imgs) {
this.mItemsImgs=imgs;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView=View.inflate(parent.getContext(),R.layout.item_recyclerview,null);
itemView.setOnClickListener(this);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.imageView.setImageResource(mItemsImgs[position]);
holder.itemView.setTag(position);
}
@Override
public int getItemCount() {
return mItemsImgs.length;
}
//声明点击事件
private interface OnRecyclerViewItemClickListener{
void onItemClick(View view,int position);
}
private OnRecyclerViewItemClickListener onRecyclerViewItemClickListener=null;
public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener listener){
this.onRecyclerViewItemClickListener=listener;
}
@Override
public void onClick(View view) {
if(onRecyclerViewItemClickListener!=null){
onRecyclerViewItemClickListener.onItemClick(view, (Integer) view.getTag());
}
}
//----
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView= (ImageView) itemView.findViewById(R.id.img_recyclerviewItem);
}
}
}
可以清楚的看到,代码的改动似乎有点大。是的,的确有点大。
首先,我们实现了View.OnClickListener,实现了他的的onClick方法。
其次,我们创建了一个OnRecyclerViewOnItemClickLister方法,并且定义了他的内部方法为onItemOnClick,这个方法接收两个对象,一个是view,一个是int position。
第三,我们声明了一个onRecyclerViewOnItemClickLister对象。
第四,暴露了一个setOnRecyclerViewItemClickListeners方法,要求传入一个OnRecyclerViewItemClickListener 对象。
第五,我们在onClick方法中调用了onRecyclerViewOnitemClickListener的onItemOnClick方法。
第六,我们在onCreateViewHolder方法中为view设置了一个onClick监听事件。
第七,在onBindViewHolder方法中为view设置tag。
只有通过以上起步,才能实现我们的点击事件,的确是有点麻烦。
最后点击的效果图
源码地址:点击打开链接