上一篇学习了下RecyclerView的基本使用,主要是一些基本操作。回顾下:
RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.
首先还是POST出我的学习链接:
http://blog.csdn.net/lmj623565791/article/details/44014941
http://blog.csdn.net/lmj623565791/article/details/51118836
https://github.com/hongyangAndroid/base-adapter
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1120/3705.html
要使用RecyclerView你需要做一些几件事情:
- 设置布局管理器LayoutManager,控制其显示的方式。
- 通过ItemDecoration来设置Item间的间隔。
- 通过ItemAnimator来设置Item间的增删动画。
- 自写RecyclerView.Adapter。
Adapter要自己来写,这多麻烦啊。还不像ListView可以使用多种适配器像ArrayAdapter、SimpleAdapter等等啊。RecyclerView还必须使用ViewHolder。但是总有大神会帮你解决这些问题的!
在RecyclerView没出来之前就有ListView的万能适配器了,既然RecyclerView相似,那么适配器上也可以有所借鉴了。
本文主要学习两种RecyclerView的万能适配器的使用,第一种是鸿洋老师写的万能适配器,第二种是陈宇明老师的万能适配器。从使用上来看陈宇明老师的适配器功能更加完善。本文只学习使用并不研究代码~
首先要使用鸿洋老师的万能适配器,你要在你的build.gradle
中添加
compile 'com.android.support:recyclerview-v7:23.2.0'//使用RecyclerView
compile 'com.zhy:base-adapter:2.0.0'//使用万能适配器
对于简单的RecyclerView即从鸿洋老师的例子来看是只有一个ItemType的RecyclerView,比如下面这种形式统一的RecyclerView。
要实现上面的效果你只需要在完成以下几件事情:
- 数据封装,以及数据集的准备。
- 设置布局管理器和分割线,通过以下代码设置:
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
如果使用CardView的话可以不设置分割线…
- 完成item_list.xml
的编写,这个就是RecylerView
每一项的布局格式,本人测试的item_list.xml
如下:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_marginTop="10dp"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/icon1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="li" />
<TextView
android:id="@+id/info1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
LinearLayout>
android.support.v7.widget.CardView>
recyclerView.setAdapter(new CommonAdapter(this, R.layout.item_list, mDatas) {
@Override
public void convert(ViewHolder holder, Persons persons) {
holder.setText(R.id.name, persons.getName());
holder.setText(R.id.info1, persons.getInfo());
holder.setImageResource(R.id.icon1, persons.getIcon());
}
});
可以看到适配器这部分的代码确实简单了很多,以往还得自己写个Adapter,现在只要将数据和相应的视图对应就可以了。相当的方便。这样的话那些数据项是统一样式的RecyclerView就能够几句话完成适配了!
针对于多个ItemViewType的RecyclerView则可以通过MutiItemCommonAdapter来实现,比如鸿洋大神Sample里的聊天记录的展示。这个的代码实现就没有上面那么简单了,需要自己写一个适配器(这也是理所应当的,不然谁知道你哪种情况下需要使用哪种视图展示啊)。
其构造适配器的步骤如下:
- 首先你的数据集肯定是要考虑到这个点的,你可以在之前的数据集中设置一个布尔值。在适配的时候进行判断!(鸿洋老师的例子),当然你也可以设置多个数据集,分别对应不同的视图。
- 之后你就需要写RecyclerView
的适配器了,继承自MultiItemCommonAdapter
,在构造器中我们要告诉代码我们有几种当时的ItemType,设置好对应关系。
- 之后在convert()
函数中完成数据项与视图的一一对应。
这个我个人感觉会用的不会很多,有很多问题我也没有问题研究。等到使用到这种方式的时候着重研究下,这里先记个笔记。
第三种,添加Header。关于给RecyclerView
添加Header的原理,请看第四篇学习博客,里面详细介绍了如何实现给RecyclerView
添加Header。其实Header同样是作为RecyclerView的一个Item来考虑的,只是我们通过ItemType
去找到它,如果是Header就设置HeaderView
如果不是Header就正常设置Item。大致的原理就是这样。
在鸿洋老师的万能适配器中,封装好后你只需要按如下步骤做就可以了:
SectionSupport sectionSupport = new SectionSupport()
{
@Override
public int sectionHeaderLayoutId()
{
return R.layout.header;
}
@Override
public int sectionTitleTextViewId()
{
return R.id.id_header_title;
}
@Override
public String getTitle(String s)
{
return s.substring(0, 1);
}
};
在上面的代码中 首先指定Header的布局,以及布局中显示标题的TextView
,以及根据Item显示什么样的标题。通过上面的 SectionSupport
来指定。这里有一点需要注意的就是,标题栏里的标题是通过getTitle()
设置的,在鸿洋老师的例子中,鸿洋老师在initData()
设置数据集的时候做了点手脚,就是每个数据就都是“A(B.C…) + 数字”,这样标题就取第一个字母就行了,但这里有两个问题不晓得是鸿洋老师例子中没有展示还是没有实现,一个是这里默认的标题是TextView
,如果是要以ImageView
作为标题呢?
第二个问题就是标题栏的标题设置有什么更好的办法吗?
在接下来就很简单了:
SectionAdapter adapter = new SectionAdapter(this, R.layout.item_list, mDatas, sectionSupport)
{
@Override
public void convert(ViewHolder holder, String s)
{
holder.setText(R.id.id_item_list_title, s);
}
};
mRecyclerView.setAdapter(adapter);
这样就完成了Header的添加。最后是鸿洋老师Sample的展示。
学习完鸿洋老师的万能适配器的使用,接下来学习下陈宇明大神的万能适配器,就例子的功能和效果来看确实要比鸿洋老师更丰富一些。使用起来也很好,但我看陈大神github首页的介绍使用的时候没有鸿洋老师来的省力,因为陈大神把很多的数据封装起来了,所以光看他的Github介绍是无法了解如何使用的,必须把他的代码Clone或者DownLoad下来看看才知道如何使用。但总的来说陈大神的万能适配器还是很好使用的。
学习链接:
http://www.jianshu.com/p/411ab861034f
http://www.jianshu.com/p/fa3f97c19263
http://www.jianshu.com/p/9d75c22f0964
http://www.jianshu.com/p/cf29d4e45536
https://github.com/CymChad/BaseRecyclerViewAdapterHelper/blob/master/README-cn.md
因为陈大神的数据全部封装起来了,我这里就不用他的例子了,我自己学习了下如何使用后,自己实践了下!
首先还是数据集的创建:
public class Persons {
private String name;
private String info;
private int icon;
public Persons(String name, String info, int icon) {
this.name = name;
this.info = info;
this.icon = icon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
这就类似陈大神例子中的Status
,然后我们就直接写QuickAdapter
了。
public class QuickAdapter extends BaseQuickAdapter<Persons> {
public QuickAdapter(int layoutResId, List data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder baseViewHolder, Persons persons) {
baseViewHolder.setText(R.id.name, persons.getName());
baseViewHolder.setText(R.id.info1, persons.getInfo());
baseViewHolder.setImageResource(R.id.icon1, persons.getIcon());
baseViewHolder.setOnClickListener(R.id.name, new OnItemChildClickListener());
// baseViewHolder.setOnClickListener(R.id.info1, new OnItemChildClickListener());
baseViewHolder.setOnClickListener(R.id.icon1, new OnItemChildClickListener());
}
}
这个RecyclerView.Adapater
基本类似,上面说的两个万能适配器都是参考
JoanZapata / base-adapter-helper
所以适配器的代码普遍相似。
然后就回到MainAcitivity
中去:
public class MainActivity extends AppCompatActivity {
private RecyclerView rv_list;
private List mDatas = new ArrayList();
private QuickAdapter mQuickAdapter;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDatas();
rv_list = (RecyclerView) findViewById(R.id.rv_list);
rv_list.setLayoutManager(new LinearLayoutManager(this));
mQuickAdapter = new QuickAdapter(R.layout.item_list, mDatas);
//添加RecyclerView的点击事件
mQuickAdapter.setOnRecyclerViewItemClickListener(new BaseQuickAdapter.OnRecyclerViewItemClickListener() {
@Override
public void onItemClick(View view, int i) {
Toast.makeText(MainActivity.this, "Item" + i + "has been clicked", Toast.LENGTH_SHORT).show();
}
});
//添加RecyclerView的长按事件
mQuickAdapter.setOnRecyclerViewItemLongClickListener(new BaseQuickAdapter.OnRecyclerViewItemLongClickListener() {
@Override
public boolean onItemLongClick(View view, int i) {
Toast.makeText(MainActivity.this, "长按", Toast.LENGTH_SHORT).show();
return true;
}
});
//添加RecyclerView的子布局多个控件的点击事件
mQuickAdapter.setOnRecyclerViewItemChildClickListener(new BaseQuickAdapter.OnRecyclerViewItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter baseQuickAdapter, View view, int i) {
switch (view.getId()){
case R.id.icon1:
Toast.makeText(MainActivity.this, "icon1" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
case R.id.name:
Toast.makeText(MainActivity.this, "name" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
case R.id.info1:
Toast.makeText(MainActivity.this, "info" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
}
}
});
mQuickAdapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);
mQuickAdapter.isFirstOnly(false);
rv_list.setAdapter(mQuickAdapter);
}
private void initDatas(){
mDatas.add(new Persons("li", "qedasc6456qdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li2", "qedascqdsa6456das", R.drawable.ic_launcher));
mDatas.add(new Persons("li3", "qed43asc754qdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li4", "qedascqdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li5", "qe43dascqd31sadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li6", "qedascqd1sad31as", R.drawable.ic_launcher));
mDatas.add(new Persons("li7", "qedascqdsa12das", R.drawable.ic_launcher));
mDatas.add(new Persons("li8", "qedascqdsa123das", R.drawable.ic_launcher));
mDatas.add(new Persons("li9", "qedascqds321adas", R.drawable.ic_launcher));
mDatas.add(new Persons("li10", "qedasc1231qdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li11", "qed3123cqdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li12", "qeewqdascqdsadas", R.drawable.ic_launcher));
mDatas.add(new Persons("li13", "qedascqds23ss", R.drawable.ic_launcher));
mDatas.add(new Persons("li14", "qedascqdsaas", R.drawable.ic_launcher));
}
}
很简单,和鸿洋老师那个万能适配器做的事情一样。但这里有两个优点,第一个添加动画方面很方便,只需要一行代码就可以搞定
quickAdapter.openLoadAnimation();
不加参数的话就是默认的动画效果,其还提供其他五种效果
BaseQuickAdapter.ALPHAIN 渐显
BaseQuickAdapter.SCALEIN 缩放
BaseQuickAdapter.SLIDEIN_BOTTOM 从下到上滑进
BaseQuickAdapter.SLIDEIN_LEFT 从左到右滑进
BaseQuickAdapter.SLIDEIN_RIGHT 从右到左滑进
第二个能够添加子布局多个控件的点击事件,这个功能应该比长按功能更来得实际。要实现也很简单:
首先在你写的Adapter中,这里即QuickAdapter
中添加控件的点击事件即可:
protected void convert(BaseViewHolder helper, Status item) {
helper.setOnClickListener(R.id.tweetAvatar, new OnItemChildClickListener())
.setOnClickListener(R.id.tweetName, new OnItemChildClickListener());
}
然后在Activity中实现子布局的控件的点击事件:
mQuickAdapter.setOnRecyclerViewItemChildClickListener(new BaseQuickAdapter.OnRecyclerViewItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter baseQuickAdapter, View view, int i) {
switch (view.getId()){
case R.id.icon1:
Toast.makeText(MainActivity.this, "icon1" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
case R.id.name:
Toast.makeText(MainActivity.this, "name" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
case R.id.info1:
Toast.makeText(MainActivity.this, "info" + i + "has been clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onItemChildClick: had been finished");
break;
}
}
});
是不是特别简单,这样感觉QQ都能自己写了呢~(开个玩笑)最后的效果如下:
接着就是多个ItemViewType的RecyclerView的使用了,实话实说,在这个方面的使用上来讲,陈大神的万能适配器真的比鸿洋老师的好用不少,还记得鸿洋老师的如何使用吗…回顾下:
- 首先你的数据集得多一个变量,作用是做判断是哪种ItemType
- 接着在Adapter里你就是对变量进行判断然后对应其ItemType
- 再接着就是每种ItemType对应一个布局了。
而陈大神的万能适配器的具体使用步骤如下:
MultiItemEntity
,因为它提供了一个setItemType
的方法,去设置每个数据的ItemTypeBaseMultiItemQuickAdapter
,这里重载实现convert()
方法。说的太虚又说不准,拿例子来说话吧。
第一步数据集的构造:
public class MutiItem extends MultiItemEntity {
public static final int SEND = 1;
public static final int FROM = 2;
private int icon;
private String name;
private String content;
private String createDate;
public MutiItem(int icon, String name, String content, String createDate) {
this.name = name;
this.icon = icon;
this.content = content;
this.createDate = createDate;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
}
这里我直接把鸿洋老师的ChatMessage
去了一个变量后直接拿来用了
前面两个常量就是ItemType。而Adapter就更简单了。只需要设置ItemType对应的视图,以及convert
里做数据填充就可以了。
public class MutiItemAdapter extends BaseMultiItemQuickAdapter<MutiItem> {
public MutiItemAdapter(Context context, List data) {
super(data);
addItemType(MutiItem.SEND, R.layout.main_chat_send_msg);
addItemType(MutiItem.FROM, R.layout.main_chat_from_msg);
}
@Override
protected void convert(BaseViewHolder baseViewHolder, MutiItem mutiItem) {
switch (baseViewHolder.getItemViewType()) {
case MutiItem.SEND:
baseViewHolder.setText(R.id.chat_send_content, mutiItem.getContent());
baseViewHolder.setText(R.id.chat_send_name, mutiItem.getName());
baseViewHolder.setImageResource(R.id.chat_send_icon, mutiItem.getIcon());
break;
case MutiItem.FROM:
baseViewHolder.setText(R.id.chat_from_content, mutiItem.getContent());
baseViewHolder.setText(R.id.chat_from_name, mutiItem.getName());
baseViewHolder.setImageResource(R.id.chat_from_icon, mutiItem.getIcon());
break;
}
}
}
然后就可以在Activity中设置RecyclerView的Adapter了。
public class MutiItemActivity extends Activity {
private RecyclerView mRecyclerView;
private List mutiItemList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mutiitem);
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
initData();
MutiItemAdapter mutiItemAdapter = new MutiItemAdapter(this, mutiItemList);
mRecyclerView.setAdapter(mutiItemAdapter);
}
private void initData(){
MutiItem item = null;
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "renma", "where are you ", null);
item.setItemType(MutiItem.FROM);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "renma", "where are you ", null);
item.setItemType(MutiItem.FROM);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "renma", "where are you ", null);
item.setItemType(MutiItem.FROM);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "renma", "where are you ", null);
item.setItemType(MutiItem.FROM);
mutiItemList.add(item);
item = new MutiItem(R.drawable.xiaohei, "xiaohei", "where are you ", null);
item.setItemType(MutiItem.SEND);
mutiItemList.add(item);
}
}
是不是超级简单,只是别忘了在数据构造的时候记得使用setItemType
。
根据官方的介绍,要添加HeaderView和FooterView,只需要两句代码就可以搞定。
mQuickAdapter.addHeaderView(getView());
mQuickAdapter.addFooterView(getView());
这里的getView()
返回的是一个View
.
如果只有一个HeaderView和FooterView那这个万能适配器就能完美实现,但像鸿洋老师那种可以添加多个HeaderView的,这边没有提及。但也不是没有解决办法,添加Header的思想其实也就是多加一个ItemType,如果真要实现分类,有多个Header的话,那就把HeaderView作为一个ItemType,指定其视图就好了~