RecyclerView 基础教程
RecyclerView是从support-v7库开始引入的,用于取代 ListView 。
相比于ListView
, RecyclerView更加灵活、高效和无限的可扩展性。
环境准备
- Windows/Mac
- Android Studio 1.4
- Android SDK
- 科学上网(开发人员必备)
首先,我们需要引入依赖库:
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:recyclerview-v7:22.2.1'
简单的 ListView 列表
我们首先来实现一个简单的 listview 列表效果:
因为此处用到了 design 库的新控件CardView
,所以我们还需要加入如下依赖库:
compile 'com.android.support:cardview-v7:22.2.1'
首先创建一个 RecyclerView 的新项目,修改我们的 activity_main.xml
代码如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.v7.widget.RecyclerView
android:id="@+id/rc_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v7.widget.RecyclerView>
</FrameLayout>
RecyclerView.Adapter
RecyclerView
的适配器实现与以往的 ListView 稍有不同,需要继承它自身特有的 RecyclerView.Adapter
,并且RecyclerView
必须通过自带的 RecyclerView.ViewHolder
来构建 Item。
adapter
基本代码如下:
public class RecyclerViewApdater extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public RecyclerViewApdater() {
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
}
@Override
public int getItemCount() {
return count;
}
}
根据代码我们可以发现和ListView
不同的是,我们重写了 onCreateViewHolder(ViewGroup parent, int viewType)
和 onBindViewHolder(RecyclerView.ViewHolder holder, int position)
。根据名字我们可知,这两个方法,一个是创建数据,一个是绑定数据。其实这两个方法干的事情和在 ListView
的 getView
方法里面做的事情一样。但是现在布局和数据分离的方式明显结构清晰多了。
onCreateViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new CardViewHolder(view);
}
onCreateViewHolder
方法的返回的参数是一个 RecyclerView.ViewHolder
,这个东西类似我们使用 ListView
的时候自定义的模板类ViewHolder
。关于RecyclerView.ViewHolder
,官方文档的介绍是 用于描述 recyclerview 里面的项目视图和元数据。如何理解这句话?通俗的讲,就是用来存储数据和布局视图的工具类。
public static class CardViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public CardViewHolder(View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.view);
mTextView = (TextView) itemView.findViewById(R.id.tv_card);
}
}
RecyclerView.ViewHolder
的构造函数需要传入一个View
作为参数。这个view
就是每一个item
显示的布局文件。我们接受到这个 view
后可以对这个view
进行一些操作,比如findViewById
出所有的子控件。这个类还封装了一些其他方法供我们使用,具体可以参考官网文档 RecyclerView.ViewHolder
。
回到onCreateViewHolder(ViewGroup parent, int viewType)
,发现参数有两个,我们主要关注第二个int viewType
,这个参数是由getItemViewType(int position)
这个方法返回的,所以我们可以通过设置type来定制出我们需要的不同 Item。
onBindViewHolder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
CardViewHolder mCardViewHolder = (CardViewHolder)holder;
mCardViewHolder.mTextView.setText("Hello CardView " + position);
}
这个方法有两个参数 RecyclerView.ViewHolder holder
和 int position
。一个就是我们的视图数据,一个是当前 item 的位置。
onCreateViewHolder
和onBindViewHolder
这两个方法是轮流调用的,先调用onCreateViewHolder
生产Item,然后调用onBindViewHolder
来对视图进行数据处理或布局变化。当滚动的时候只会调用onBindViewHolder
显示数据。也就是说RecyclerView
会自动去缓存布局并且复用。
关于 RecyclerView 换成机制的问题,可以参考 http://lujun.co/2015/06/29/对recyclerview的一点探讨/
RecyclerViewApdater的问完整代码如下:
public class RecyclerViewApdater extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
int count = 0;
public RecyclerViewApdater() {
}
public RecyclerViewApdater(int size) {
count = size;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new CardViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
CardViewHolder mCardViewHolder = (CardViewHolder)holder;
mCardViewHolder.mTextView.setText("Hello CardView " + position);
}
public boolean isHeaderPosition(int position){
return position == 0;
}
@Override
public int getItemCount() {
return count;
}
public static class CardViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public CardViewHolder(View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.view);
mTextView = (TextView) itemView.findViewById(R.id.tv_card);
}
}
public static class CardViewHeaderHolder extends RecyclerView.ViewHolder {
public CardViewHeaderHolder(View itemView) {
super(itemView);
}
}
}
LayoutManager
使用RecyclerView
一定要通过setLayoutManager
来设置布局类别。目前 support v7库提供了三种布局供我们使用。
- LinearLayoutManager 线性布局,比如
ListView
效果我们就需要使用这种 - GridLayoutManager 九宫格布局,类似
GridView
- StaggeredGridLayoutManager 瀑布流效果
因为我们需要实现ListView
效果,所以我们代码如下:
public class MainActivity extends AppCompatActivity {
private FrameLayout drawerlayout;
private android.support.v7.widget.RecyclerView rccontent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.rccontent = (RecyclerView) findViewById(R.id.rc_content);
this.drawerlayout = (FrameLayout) findViewById(R.id.drawer_layout);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setHomeButtonEnabled(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
// GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
// StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, 1);
RecyclerViewApdater recyclerViewApdater = new RecyclerViewApdater(20);
rccontent.setLayoutManager(linearLayoutManager);
rccontent.setAdapter(recyclerViewApdater);
}
}
onItemClickListener
我们会发现RecyclerView
并没有提供onItemClickListener
事件监听,如果我们需要在Activity
里面监听 Item 的点击事件。可以通过接口回调的方式来实现。
在RecyclerView.Adapter
里面添加接口
public interface onItemClickLintener{
public void onItemClick(View v, int position);
}
添加接口方法
private static onItemClickLintener mLintener = null;
public void setOnItemClickLintener(onItemClickLintener mItemClick){
this.mLintener = mItemClick;
}
在RecyclerView.ViewHolder
中接受事件
public static class CardViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public CardViewHolder(final View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.view);
mTextView = (TextView) itemView.findViewById(R.id.tv_card);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mLintener != null) {
mLintener.onItemClick(view, getAdapterPosition());
}
}
});
}
}
通过RecyclerViewApdater
来使用
RecyclerViewApdater recyclerViewApdater = new RecyclerViewApdater(20);
recyclerViewApdater.setOnItemClickLintener(new RecyclerViewApdater.onItemClickLintener() {
@Override
public void onItemClick(View v, int position) {
Log.d("demo", "------ " + position);
}
});