RecyclerView总结学习(二)

RecyclerView总结学习(二)

前言

上一篇学习了下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中添加

1
2
compile 'com.android.support:recyclerview-v7:23.2.0'//使用RecyclerView
compile 'com.zhy:base-adapter:2.0.0'//使用万能适配器

对于简单的RecyclerView即从鸿洋老师的例子来看是只有一个ItemType的RecyclerView,比如下面这种形式统一的RecyclerView。
enter image description here

要实现上面的效果你只需要在完成以下几件事情:

  • 数据封装,以及数据集的准备。
  • 设置布局管理器和分割线,通过以下代码设置:
    1
    2
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));

如果使用CardView的话可以不设置分割线…

  • 完成item_list.xml的编写,这个就是RecylerView每一项的布局格式,本人测试的item_list.xml如下:

    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
    29
    30
    31
    32
    	<?xml version="1.0" encoding="utf-8"?>
    <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>
  • 使用万能适配器,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    recyclerView.setAdapter(new CommonAdapter<Persons>(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就能够几句话完成适配了!

多个ItemViewTyped的RecyclerView

针对于多个ItemViewType的RecyclerView则可以通过MutiItemCommonAdapter来实现,比如鸿洋大神Sample里的聊天记录的展示。这个的代码实现就没有上面那么简单了,需要自己写一个适配器(这也是理所应当的,不然谁知道你哪种情况下需要使用哪种视图展示啊)。
其构造适配器的步骤如下:

  • 首先你的数据集肯定是要考虑到这个点的,你可以在之前的数据集中设置一个布尔值。在适配的时候进行判断!(鸿洋老师的例子),当然你也可以设置多个数据集,分别对应不同的视图。
  • 之后你就需要写RecyclerView的适配器了,继承自MultiItemCommonAdapter,在构造器中我们要告诉代码我们有几种当时的ItemType,设置好对应关系。
  • 之后在convert()函数中完成数据项与视图的一一对应。

这个我个人感觉会用的不会很多,有很多问题我也没有问题研究。等到使用到这种方式的时候着重研究下,这里先记个笔记。

带Header的RecyclerView

第三种,添加Header。关于给RecyclerView添加Header的原理,请看第四篇学习博客,里面详细介绍了如何实现给RecyclerView添加Header。其实Header同样是作为RecyclerView的一个Item来考虑的,只是我们通过ItemType去找到它,如果是Header就设置HeaderView如果不是Header就正常设置Item。大致的原理就是这样。

在鸿洋老师的万能适配器中,封装好后你只需要按如下步骤做就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	SectionSupport<String> sectionSupport = new SectionSupport<String>()
{
@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作为标题呢?
第二个问题就是标题栏的标题设置有什么更好的办法吗?

在接下来就很简单了:

1
2
3
4
5
6
7
8
9
10
SectionAdapter<String> adapter = new SectionAdapter<String>(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的展示。
enter image description here

万能适配器(二)

使用方法

学习完鸿洋老师的万能适配器的使用,接下来学习下陈宇明大神的万能适配器,就例子的功能和效果来看确实要比鸿洋老师更丰富一些。使用起来也很好,但我看陈大神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

因为陈大神的数据全部封装起来了,我这里就不用他的例子了,我自己学习了下如何使用后,自己实践了下!

首先还是数据集的创建:

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
29
30
31
32
33
34
35
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了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class QuickAdapter extends BaseQuickAdapter<Persons> {


public QuickAdapter(int layoutResId, List<Persons> 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中去:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class MainActivity extends AppCompatActivity {

private RecyclerView rv_list;
private List<Persons> mDatas = new ArrayList<Persons>();
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中添加控件的点击事件即可:

1
2
3
4
protected void convert(BaseViewHolder helper, Status item) {
helper.setOnClickListener(R.id.tweetAvatar, new OnItemChildClickListener())
.setOnClickListener(R.id.tweetName, new OnItemChildClickListener());
}

然后在Activity中实现子布局的控件的点击事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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都能自己写了呢~(开个玩笑)最后的效果如下:
enter image description here

多个ItemViewTyped的RecyclerView

接着就是多个ItemViewType的RecyclerView的使用了,实话实说,在这个方面的使用上来讲,陈大神的万能适配器真的比鸿洋老师的好用不少,还记得鸿洋老师的如何使用吗…回顾下:

  • 首先你的数据集得多一个变量,作用是做判断是哪种ItemType
  • 接着在Adapter里你就是对变量进行判断然后对应其ItemType
  • 再接着就是每种ItemType对应一个布局了。

而陈大神的万能适配器的具体使用步骤如下:

  • 首先也是需要一个数据集的,当然这个数据集也得给出ItemType,但不需要多余的变量来进行判断。这里需要注意的是这个数据集必须继承自MultiItemEntity,因为它提供了一个setItemType的方法,去设置每个数据的ItemType
  • 再来就是编写Adapter了,这个适配器得继承自BaseMultiItemQuickAdapter<T>,这里重载实现convert()方法。

说的太虚又说不准,拿例子来说话吧。
第一步数据集的构造:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
	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里做数据填充就可以了。

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
	public class MutiItemAdapter extends BaseMultiItemQuickAdapter<MutiItem> {


public MutiItemAdapter(Context context, List<MutiItem> 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了。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
	public class MutiItemActivity extends Activity {
private RecyclerView mRecyclerView;
private List<MutiItem> mutiItemList = new ArrayList<MutiItem>();

@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

带Header的RecyclerView

根据官方的介绍,要添加HeaderView和FooterView,只需要两句代码就可以搞定。

1
2
mQuickAdapter.addHeaderView(getView());
mQuickAdapter.addFooterView(getView());

这里的getView()返回的是一个View.

如果只有一个HeaderView和FooterView那这个万能适配器就能完美实现,但像鸿洋老师那种可以添加多个HeaderView的,这边没有提及。但也不是没有解决办法,添加Header的思想其实也就是多加一个ItemType,如果真要实现分类,有多个Header的话,那就把HeaderView作为一个ItemType,指定其视图就好了~