android封装adapter,Android RecyclerView中Adapter和ViewHolder的封装

前情提要

最近项目我在项目中使用了RecyclerView代替了ListView.由于项目中有多出列表项使用RecyclerView,这就导致需要写多个Adapter和ViewHolder.

其实,怎么说呢?就是懒,想少写代码,所以想研究一下能否简化一下.

具体实现

封装分为Adapter和ViewHolder两部分,如下所示.

ViewHolder

抽象类BaseHolder继承RecyclerView.ViewHolder,并依赖注入的数据类型M,即和ViewHolder绑定的数据类型为M.

该抽象类包含一个构造方法,用于获取item对应的布局.一个抽象函数用于将数据设置到item上面.

[代码]java代码:01

02

03

04

05

06

07

08

09

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/**

* 基础的ViewHolder

* Created by zyz on 2016/5/17.

*/

public abstract class BaseHolder extends RecyclerView.ViewHolder   {

public BaseHolder(ViewGroup   parent, @LayoutRes int resId) {

super(LayoutInflater.from(parent.getContext()).inflate(resId,   parent, false));

}

/**

* 获取布局中的View

* @param viewId view的Id

* @param View的类型

* @return view

*/

protected T getView(@IdRes int viewId){

return (T)   (itemView.findViewById(viewId));

}

/**

* 获取Context实例

* @return context

*/

protected Context getContext()   {

return itemView.getContext();

}

/**

* 设置数据

* @param data 要显示的数据对象

*/

public abstract void setData(M   data);

}

Adapter

Adapter类也为抽象类,继承于RecyclerView.Adapter,并绑定了两个泛型:

1.   M : 用于该 Adapter 的列表的数据类型,即List.

2.   H : 即和 Adapter 绑定的 Holder 的类型.

并且,该 Adapter 自带 List 数据集合,声明时可以不用传递数据集合.也包含了 List 的相关操作.同时还给该 Adapter 绑定了一个 item 的点击事件,且为可选操作,不需要点击操作,直接传null即可.

[代码]java代码:001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118/**

* 基础的Adapter

* Created by zyz on 2016/5/17.

*/

public abstract class BaseAdapter> extends RecyclerView.Adapter {

protected List   dataList;

protected OnItemClickListener   listener;

/**

* 设置数据,并设置点击回调接口

*

* @param list 数据集合

* @param listener 回调接口

*/

public BaseAdapter(@Nullable List   list, @Nullable OnItemClickListener listener) {

this.dataList   = list;

if (this.dataList   == null) {

this.dataList   = new ArrayList<>();

}

this.listener   = listener;

}

@Override

public void onBindViewHolder(final   H holder, int position) {

holder.setData(dataList.get(position));

if (listener   != null) {

holder.itemView.setOnClickListener(new   View.OnClickListener() {

@Override

public   void onClick(View v) {

listener.onItemClick(holder);

}

});

}

}

@Override

public int getItemCount() {

return dataList.size();

}

/**

* 填充数据,此方法会清空以前的数据

*

* @param list 需要显示的数据

*/

public void fillList(List   list) {

dataList.clear();

dataList.addAll(list);

}

/**

* 更新数据

*

* @param holder item对应的holder

* @param data     item的数据

*/

public void updateItem(H   holder, M data) {

dataList.set(holder.getLayoutPosition(),   data);

}

/**

* 获取一条数据

*

* @param holder item对应的holder

* @return 该item对应的数据

*/

public M getItem(H holder) {

return dataList.get(holder.getLayoutPosition());

}

/**

* 获取一条数据

*

* @param position item的位置

* @return item对应的数据

*/

public M getItem(int position)   {

return dataList.get(position);

}

/**

* 追加一条数据

*

* @param data 追加的数据

*/

public void appendItem(M data)   {

dataList.add(data);

}

/**

* 追加一个集合数据

*

* @param list 要追加的数据集合

*/

public void appendList(List   list) {

dataList.addAll(list);

}

/**

* 在最顶部前置数据

*

* @param data 要前置的数据

*/

public void preposeItem(M data)   {

dataList.add(0,   data);

}

/**

* 在顶部前置数据集合

*

* @param list 要前置的数据集合

*/

public void preposeList(List   list) {

dataList.addAll(0,   list);

}

}

使用范例

使用范例为一种Item和多种Item这两种类型.

一种Item

运行结果如下图所示:

单个Item类型的ViewHolder如下:

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22/**

* 一种View的Holder

* Created by zyz on 2016/5/17.

*/

public class SingleHolder extends BaseHolder   {

TextView nameView;

TextView ageView;

public SingleHolder(ViewGroup   parent, @LayoutRes int resId) {

super(parent,   resId);

nameView   = getView(R.id.name_tv);

ageView   = getView(R.id.age_tv);

}

@Override

public void setData(Person   data) {

nameView.setText(data.getName());

ageView.setText(String.valueOf(data.getAge()));

}

}

与之对应的Adapter如下:

[代码]java代码:01

02

03

04

05

06

07

08

09

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/**

* 一种item的Adapter

* Created by zyz on 2016/5/17.

*/

public class SingleAdapter extends BaseAdapter {

public SingleAdapter(SingleItemClickListener   listener) {

super(null,   listener);

}

@Override

public SingleHolder   onCreateViewHolder(ViewGroup parent, int viewType) {

return new   SingleHolder(parent, R.layout.item_single);

}

@Override

public void onBindViewHolder(final   SingleHolder holder, int position) {

super.onBindViewHolder(holder,   position);

holder.nameView.setOnClickListener(new   View.OnClickListener() {

@Override

public   void onClick(View v) {

((SingleItemClickListener)   listener).onNameClick(getItem(holder).getName());

}

});

holder.ageView.setOnClickListener(new   View.OnClickListener() {

@Override

public   void onClick(View v) {

((SingleItemClickListener)   listener).onAgeClick(getItem(holder).getAge());

}

});

}

public interface SingleItemClickListener   extends OnItemClickListener {

void onNameClick(String   name);

void onAgeClick(int   age);

}

}

多种Item

运行结果如下图所示:

多个Item的ViewHolder的写法,可以根据Item的View重合度来写:

1.   如果多个item完全没有相同的部分,则单独继承ViewHolder

2.   如果Item之间有相同的部分,可以抽出来一个父类来继承ViewHolder

这里的范例Item是具有重合部分的.模型来自聊天界面.

[代码]java代码:1

2

3

4

5

6

7

8

9Holder部分如下:

|-ChatHolder //聊天View的Holder,包含公共部分

|-TextHolder //文字消息的Holder,包含文字特有的部分

|-ImageHolder //图片消息的Holder,包含图片特有的部分.

数据部分如下:

|-ChatMsg //代表一条聊天消息

|-TextMsg //代表一条文字消息

|-ImageMsg //代表一条图片消息

ChatHolder代码如下,包含发送者的名称和时间:

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22/**

* 聊天界面的ViewHolder

* Created by zyz on 2016/5/18.

*/

public class ChatHolder extends BaseHolder   {

TextView senderNameTv;

TextView createTimeTv;

public ChatHolder(ViewGroup   parent, @LayoutRes int resId) {

super(parent,   resId);

senderNameTv   = getView(R.id.name_tv);

createTimeTv   = getView(R.id.create_time_tv);

}

@Override

public void setData(ChatMsg   data) {

senderNameTv.setText(data.getSenderName());

createTimeTv.setText(data.getCreateTime());

}

}

TextHolder的代码如下,包含文本显示的View

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20/**

* 文本消息的Holder

* Created by zyz on 2016/5/18.

*/

public class TextHolder extends ChatHolder {

TextView contentTv;

public TextHolder(ViewGroup   parent, @LayoutRes int resId) {

super(parent,   resId);

contentTv   = getView(R.id.content_tv);

}

@Override

public void setData(ChatMsg   data) {

super.setData(data);

contentTv.setText(((TextMsg)data).getText());

}

}

其中的setData()方法默认调用父类的方法,可以直接设置发送者的名称和时间.

ImageHolder的代码如下,包含显示图片的View

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19/**

* 表情消息的Holder

* Created by zyz on 2016/5/18.

*/

public class ImageHolder extends ChatHolder {

ImageView contentIv;

public ImageHolder(ViewGroup   parent, @LayoutRes int resId) {

super(parent,   resId);

contentIv   = getView(R.id.content_iv);

}

@Override

public void setData(ChatMsg   data) {

super.setData(data);

contentIv.setImageResource(((ImageMsg)data).getResId());

}

}

最后是我们的Adapter,代码不多.

```java

/**

·         聊天界面的Adapter

·         Created by zyz on 2016/5/18.

*/

public class ChatAdapter extends BaseAdapter {

private static final int VIEW_TEXT = 0;

private static final int VIEW_IMAGE = 1;

public ChatAdapter(OnItemClickListener listener) {

super(null, listener);

}

@Override

public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType) {

ChatHolder holder;

if (viewType == VIEW_IMAGE) {

holder = new ImageHolder(parent, R.layout.item_msg_img_left);

} else {

holder = new TextHolder(parent, R.layout.item_msg_text_left);

}

return holder;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值