最近项目我在项目中使用了RecyclerView
代替了ListView
.因为项目中有多出列表项使用RecyclerView
,这就致使须要写多个Adapter
和ViewHolder
.java
其实,怎么说呢?就是懒,想少写代码,因此想研究一下可否简化一下.git
封装分为Adapter
和ViewHolder
两部分,以下所示.github
抽象类BaseHolder
继承RecyclerView.ViewHolder
,并依赖注入的数据类型M
,即和ViewHolder
绑定的数据类型为M.微信
该抽象类包含一个构造方法,用于获取item对应的布局.一个抽象函数用于将数据设置到item上面.app
/** * 基础的ViewHolder * Created by zyz on 2016/5/17. */ public abstract class BaseHolder<M> 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 <T> View的类型 * @return view */ protected <T extends View>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
类也为抽象类,继承于RecyclerView.Adapter
,并绑定了两个泛型:ide
M : 用于该 Adapter 的列表的数据类型,即List<M>
.函数
H : 即和 Adapter 绑定的 Holder 的类型.布局
而且,该 Adapter 自带 List 数据集合,声明时能够不用传递数据集合.也包含了 List 的相关操做.同时还给该 Adapter 绑定了一个 item 的点击事件,且为可选操做,不须要点击操做,直接传null
便可.this
/** * 基础的Adapter * Created by zyz on 2016/5/17. */ public abstract class BaseAdapter<M, H extends BaseHolder<M>> extends RecyclerView.Adapter<H> { protected List<M> dataList; protected OnItemClickListener<H> listener; /** * 设置数据,并设置点击回调接口 * * @param list 数据集合 * @param listener 回调接口 */ public BaseAdapter(@Nullable List<M> list, @Nullable OnItemClickListener<H> 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<M> 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<M> list) { dataList.addAll(list); } /** * 在最顶部前置数据 * * @param data 要前置的数据 */ public void preposeItem(M data) { dataList.add(0, data); } /** * 在顶部前置数据集合 * * @param list 要前置的数据集合 */ public void preposeList(List<M> list) { dataList.addAll(0, list); } }
使用范例为一种Item和多种Item这两种类型.spa
运行结果以下图所示:
单个Item类型的ViewHolder以下:
/** * 一种View的Holder * Created by zyz on 2016/5/17. */ public class SingleHolder extends BaseHolder<Person> { 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以下:
/** * 一种item的Adapter * Created by zyz on 2016/5/17. */ public class SingleAdapter extends BaseAdapter<Person, SingleHolder> { 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<SingleHolder> { void onNameClick(String name); void onAgeClick(int age); } }
运行结果以下图所示:
多个Item的ViewHolder的写法,能够根据Item的View重合度来写:
若是多个item彻底没有相同的部分,则单独继承ViewHolder
若是Item之间有相同的部分,能够抽出来一个父类来继承ViewHolder
这里的范例Item是具备重合部分的.模型来自聊天界面.
Holder部分以下: |-ChatHolder //聊天View的Holder,包含公共部分 |-TextHolder //文字消息的Holder,包含文字特有的部分 |-ImageHolder //图片消息的Holder,包含图片特有的部分. 数据部分以下: |-ChatMsg //表明一条聊天消息 |-TextMsg //表明一条文字消息 |-ImageMsg //表明一条图片消息
ChatHolder
代码以下,包含发送者的名称和时间:
/** * 聊天界面的ViewHolder * Created by zyz on 2016/5/18. */ public class ChatHolder extends BaseHolder<ChatMsg> { 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
/** * 文本消息的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
/** * 表情消息的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,代码很少.
/** * 聊天界面的Adapter * Created by zyz on 2016/5/18. */ public class ChatAdapter extends BaseAdapter<ChatMsg, ChatHolder> { private static final int VIEW_TEXT = 0; private static final int VIEW_IMAGE = 1; public ChatAdapter(OnItemClickListener<ChatHolder> 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; } @Override public int getItemViewType(int position) { if (getItem(position).getMsgType() == ChatMsg.TYPE_TEXT) { return VIEW_TEXT; } else { return VIEW_IMAGE; } } }
上述设置的有时间监听,则对应的事件处理在Activity中完成
chatAdapter = new ChatAdapter(new OnItemClickListener<ChatHolder>() { @Override public void onItemClick(ChatHolder holder) { //处理事件 } });
以上就是对ViewHolder和Adapter的简易封装,之后会根据须要继续封装简化.
代码地址以下:https://github.com/Dev-Wiki/RecyclerView
更多文章请移步个人博客:DevWiki Blog
重要说明
想随时获取最新博客文章更新,请关注公共帐号DevWiki,或扫描下面的二维码: