标签:android listview recyclerview
RecyclerView是android5.0提供的新组件(最新的support.v7中也提供了该组件),类似于ListView,但是比ListView更灵活、更先进,我觉得主要表现在以下几个方面:
1、 把ViewHolder的实现封装起来,规范了ViewHolder,把item的view写入ViewHolder中,通过复用ViewHolder来实现view的复用。
2、 RecyclerView.Adapter中把view的回收和内容改变等操作分开解耦了,比传统的Adapter更为灵活。
3、 独立的LayoutManager,可以灵活的控制RecyclerView中items的布局:LinearLayoutManager(垂直布局、水平布局)、GridLayoutManager(网格布局)、StaggeredGridLayoutManager(瀑布流布局);
4、 提供了RecyclerView.ItemAnimator可以设置items增加、删除时的动画(默认已有定义了动画);
下面通过官方例子来看一下RecyclerView的使用。
1、 布局文件xml的编写,没什么好说的。
<android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/>
2、在activity中使用RecyclerView
public class MyActivity extends Activity { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); // use a linear layout manager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); // specify an adapter (see also next example) mAdapter = new MyAdapter(myDataset); mRecyclerView.setAdapter(mAdapter); } ... }
代码很简单,看一下我们使用到RecyclerView的几个地方:首先是mRecyclerView.setHasFixedSize(true),从上面的注释可以知道,如果item的内容不改变view布局大小,那使用这个设置可以提高RecyclerView的效率。接着再看mLayoutManager = new LinearLayoutManager(this);mRecyclerView.setLayoutManager(mLayoutManager),这里就使用LayoutManager来控制item的排列方式,这里用的是LinearLayoutManager,也就是线性布局,默认是垂直布局,如果要设置成水平布局,只需在把new LinearLayoutManager(this)改成newLinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false)就可以了,最后一项如果为true的话,item会反向排列。
3、编写Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private String[] mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView mTextView; public ViewHolder(TextView v) { super(v); mTextView = v; } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset) { mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); // set the view's size, margins, paddings and layout parameters ... ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } }
首先看一下ViewHolder,这里不再是自己随便定义的ViewHolder了,而是继承了RecyclerView.ViewHolder,规范了ViewHolder。不同于传统的Adapter,这里没有getView,取而代之的是onCreateViewHolder和onBindViewHolder,把view的复用和数据的绑定解耦开了。
上面就是官方的简单例子,接下来我们来实现两个比较常用的功能,item的点击和上拉加载。
RecyclerView并没有提供item的点击事件,这也让我们有了多种实现方式,不管什么方式,归根到底就是对view的点击事件。我们可以在Adapter中添加对view的点击事件,有两个地方可以添加,大家看哪种方法更好。
1、 在ViewHolder中添加。
public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView mTextView; public ViewHolder(TextView v) { super(v); mTextView = v; v. setOnClickListener…. } }
2、 在onBindViewHolder中添加。
@Override public void onBindViewHolder(ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]); holder.itemView.setOnClickListener…; }
再来看看上拉加载更多,我觉得最好的方法就是在onBindViewHolder添加对上拉加载事件的判断,因为如果用传统的监听scroll的方法来做的话,那么如果我改变了LayoutManager,从垂直线性布局改成水平线性布局,或者从线性布局改成网格布局,那么对scroll监听的方法又得重新写了。下面看下具体的写法。
@Override public void onBindViewHolder(ViewHolder holder, int position) { if (position == list.size() - 1&&onLoadListener!=null&&(list.size()%limit)==0) { onLoadListener.load(); Log.i("zhuang","触发"); } }
如果当前绑定的ViewHolder的position是最后一项,则触发加载更多。这里的onLoadListener是我自定义加载接口
public interface OnLoadListener { public void load(); }
在Adapter中定义OnLoadListener变量,然后生成get和set方法,我们在activity中可以通过adapter.setOnLoadListener来为加载更多设置加载的具体实现。(list.size()%limit)==0)中的limit是每次加载的item数量,如果list.size()%limit)==0,表示每次从服务器加载的item数和我们请求的item数是一样的,证明还有其他记录,再次把list拉到最后面的item时,我们可以继续触发load方法,如果list.size()%limit)!=0,则说明我们从服务器加载过来的item数和我们请求的item数不一样,那么证明数据已经全部都加载完了,没必要再次请求了,就算list拉到最后一项,也不再请求。当然还有一种情况就是加载的数据数和我们请求的数据数是一样的,而刚好也请求完所有数据,这时候我们上拉到最后一项时,还会再触发一次加载。
下面贴上稍微完整的代码
OnLoadListener:
public interface OnLoadListener { public void load(); }
MyActivity
public class MyActivity extends Activity { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; private String[] myDataset = {...}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); // use a linear layout manager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); // specify an adapter (see also next example) mAdapter = new MyAdapter(myDataset,limit); mAdapter.setOnLoadListener(new OnLoadListener() { @Override public void load() { ... } }); mRecyclerView.setAdapter(mAdapter); } ... }
MyAdapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private String[] mDataset; private OnLoadListener onLoadListener; private int limit; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView mTextView; public ViewHolder(TextView v) { super(v); mTextView = v; } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset,int limit) { this.mDataset = myDataset; this.limit = limit; } // Create new views (invoked by the layout manager) @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); // set the view's size, margins, paddings and layout parameters ... ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]); holder.itemView.setOnClickListener(...); if (position == list.size() - 1&&onLoadListener!=null&&(list.size()%limit)==0) { onLoadListener.load(); Log.i("zhuang","触发"); } } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } }
标签:android listview recyclerview
原文地址:http://blog.csdn.net/weihuangcool/article/details/46238063