转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html

很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时给大家带来RecyclerView的适配器,楼主对期待的小伙伴表示最深刻地歉意。

如果你没有看前面的万能的ListView,GridView等的万能适配器,楼主推荐你去看一看,当然,大牛就免了。

另外,楼主今天在构思这个RecyclerView的过程中发现前天写的ListView有点毛病,现在楼主已经更改了,并且重新提交到了github,有需要的小伙伴自己去抓紧看吧。

这里是直通车:http://www.cnblogs.com/liushilin/p/5716306.html

RecyclerView也出来这么久了,虽不说大家都耳熟能详,但是至少还是很有影响力的,毕竟官方是推出来替代过往的ListView,GridView等列表显示控件的,自然有她神奇的地方。我们肯定得紧跟时代的步伐嘛。

对RecyclerView的简单使用还不了解的小伙伴,我推荐你去看一看我之前写的RecyclerView的简单使用,虽说可能不如大牛们写的面面俱到,全是精髓,但是我相信一定有它存在的意义。传送门:http://www.cnblogs.com/liushilin/p/5673833.html

简单上个运行图:

好了,大都不多说。直入今天的正题——偷懒神器,RecyclerView万能适配器的简单构造思路。

其实多半还是和之前构造ListView的万能适配器差不多哈,毕竟RecyclerView就是为了替代它们出现的,只是RecyclerView封装了ViewHolder而已,而我们要实现把ViewHolder和Adaper封装成一个万能的适配器,我们肯定还是得像上篇提到的利用每个view独一无二的id进行键值映射来做处理,当然我们还是用现在官方推荐的SparseArray,这个东西在能替代HashMap的时候真的好用,性能的优化就不用多说了。

先看看核心代码:

我们封装了ViewHolder,为了把设置值等都封装进去,我们对外提供了set方法。通过一个getView来实现之前类似于ViewHolder的设置标签的效果。如果已经绑定,则直接返回,否则放到SparseArray中。

下面是ViewHolder的基本封装。如果你有之前ListView的ViewHolder的封装,这个看起来我相信很好理解。

  1. package com.example.nanchen.commonadaperrecyclerdemo;
  2.  
  3. import android.content.Context;
  4. import android.graphics.Bitmap;
  5. import android.support.v7.widget.RecyclerView;
  6. import android.util.SparseArray;
  7. import android.view.View;
  8. import android.widget.ImageView;
  9. import android.widget.TextView;
  10.  
  11. import com.squareup.picasso.Picasso;
  12.  
  13. /**
  14. * 万能的RecyclerView的ViewHolder
  15. * Created by 南尘 on 16-7-30.
  16. */
  17. public class BaseRecyclerHolder extends RecyclerView.ViewHolder {
  18.  
  19. private SparseArray<View> views;
  20. private Context context;
  21.  
  22. private BaseRecyclerHolder(Context context,View itemView) {
  23. super(itemView);
  24. this.context = context;
  25. //指定一个初始为8
  26. views = new SparseArray<>(8);
  27. }
  28.  
  29. /**
  30. * 取得一个RecyclerHolder对象
  31. * @param context 上下文
  32. * @param itemView 子项
  33. * @return 返回一个RecyclerHolder对象
  34. */
  35. public static BaseRecyclerHolder getRecyclerHolder(Context context,View itemView){
  36. return new BaseRecyclerHolder(context,itemView);
  37. }
  38.  
  39. public SparseArray<View> getViews(){
  40. return this.views;
  41. }
  42.  
  43. /**
  44. * 通过view的id获取对应的控件,如果没有则加入views中
  45. * @param viewId 控件的id
  46. * @return 返回一个控件
  47. */
  48. @SuppressWarnings("unchecked")
  49. public <T extends View> T getView(int viewId){
  50. View view = views.get(viewId);
  51. if (view == null ){
  52. view = itemView.findViewById(viewId);
  53. views.put(viewId,view);
  54. }
  55. return (T) view;
  56. }
  57.  
  58. /**
  59. * 设置字符串
  60. */
  61. public BaseRecyclerHolder setText(int viewId,String text){
  62. TextView tv = getView(viewId);
  63. tv.setText(text);
  64. return this;
  65. }
  66.  
  67. /**
  68. * 设置图片
  69. */
  70. public BaseRecyclerHolder setImageResource(int viewId,int drawableId){
  71. ImageView iv = getView(viewId);
  72. iv.setImageResource(drawableId);
  73. return this;
  74. }
  75.  
  76. /**
  77. * 设置图片
  78. */
  79. public BaseRecyclerHolder setImageBitmap(int viewId, Bitmap bitmap){
  80. ImageView iv = getView(viewId);
  81. iv.setImageBitmap(bitmap);
  82. return this;
  83. }
  84.  
  85. /**
  86. * 设置图片
  87. */
  88. public BaseRecyclerHolder setImageByUrl(int viewId,String url){
  89. Picasso.with(context).load(url).into((ImageView) getView(viewId));
  90. // ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
  91. // ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
  92. return this;
  93. }
  94. }

然后是Recycler的Adapter,由于RecyclerView的Adapter必须继承自RecyclerView.Adapter,并且指定我们写的ViewHolder为泛型,为了达到万能的效果,我们把需要传入的Java Bean属性直接用一个泛型T指代。

下面这些值得你注意:

1)RecyclerView没有提供Item的点击事件,所以我们需要自己自定义,建议实现在Adapter中,因为adapter里面会用到ViewHolder,这样有助用我们写每一项的点击事件。

2)RecyclerView不仅支持全局刷新,而且支持局部刷新,所以我们建议把添加和删除的方法直接写在Adapter中。

3)我们为了达到万能的效果,所以我们把设置holder的方法作为一个抽象方法,方面我们通过viewId传值到相应的控件中,把整个Adapter变成一个抽象方法,这样在子类中就可以去通过强制实现的方式把我们的数据填充进去。

还是直接看源码吧。

  1. package com.example.nanchen.commonadaperrecyclerdemo;
  2.  
  3. import android.content.Context;
  4. import android.support.v7.widget.RecyclerView;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8.  
  9. import java.util.List;
  10.  
  11. /**
  12. * 万能的RecyclerView适配器
  13. * Created by 南尘 on 16-7-30.
  14. */
  15. public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerHolder> {
  16.  
  17. private Context context;//上下文
  18. private List<T> list;//数据源
  19. private LayoutInflater inflater;//布局器
  20. private int itemLayoutId;//布局id
  21. private boolean isScrolling;//是否在滚动
  22. private OnItemClickListener listener;//点击事件监听器
  23. private OnItemLongClickListener longClickListener;//长按监听器
  24. private RecyclerView recyclerView;
  25.  
  26. //在RecyclerView提供数据的时候调用
  27. @Override
  28. public void onAttachedToRecyclerView(RecyclerView recyclerView) {
  29. super.onAttachedToRecyclerView(recyclerView);
  30. this.recyclerView = recyclerView;
  31. }
  32.  
  33. @Override
  34. public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
  35. super.onDetachedFromRecyclerView(recyclerView);
  36. this.recyclerView = null;
  37. }
  38.  
  39. /**
  40. * 定义一个点击事件接口回调
  41. */
  42. public interface OnItemClickListener {
  43. void onItemClick(RecyclerView parent, View view, int position);
  44. }
  45.  
  46. public interface OnItemLongClickListener {
  47. boolean onItemLongClick(RecyclerView parent, View view, int position);
  48. }
  49.  
  50. /**
  51. * 插入一项
  52. *
  53. * @param item
  54. * @param position
  55. */
  56. public void insert(T item, int position) {
  57. list.add(position, item);
  58. notifyItemInserted(position);
  59. }
  60.  
  61. /**
  62. * 删除一项
  63. *
  64. * @param position 删除位置
  65. */
  66. public void delete(int position) {
  67. list.remove(position);
  68. notifyItemRemoved(position);
  69. }
  70.  
  71. public BaseRecyclerAdapter(Context context, List<T> list, int itemLayoutId) {
  72. this.context = context;
  73. this.list = list;
  74. this.itemLayoutId = itemLayoutId;
  75. inflater = LayoutInflater.from(context);
  76.  
  77. // recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
  78. // @Override
  79. // public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
  80. // super.onScrollStateChanged(recyclerView, newState);
  81. // isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE);
  82. // if (!isScrolling) {
  83. // notifyDataSetChanged();
  84. // }
  85. // }
  86. // });
  87. }
  88.  
  89. @Override
  90. public BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  91. View view = inflater.inflate(itemLayoutId, parent, false);
  92. return BaseRecyclerHolder.getRecyclerHolder(context, view);
  93. }
  94.  
  95. @Override
  96. public void onBindViewHolder(final BaseRecyclerHolder holder, int position) {
  97.  
  98. if (listener != null){
  99. holder.itemView.setBackgroundResource(R.drawable.recycler_bg);//设置背景
  100. }
  101. holder.itemView.setOnClickListener(new View.OnClickListener() {
  102. @Override
  103. public void onClick(View view) {
  104. if (listener != null && view != null && recyclerView != null) {
  105. int position = recyclerView.getChildAdapterPosition(view);
  106. listener.onItemClick(recyclerView, view, position);
  107. }
  108. }
  109. });
  110.  
  111. holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
  112. @Override
  113. public boolean onLongClick(View view) {
  114. if (longClickListener != null && view != null && recyclerView != null) {
  115. int position = recyclerView.getChildAdapterPosition(view);
  116. longClickListener.onItemLongClick(recyclerView, view, position);
  117. return true;
  118. }
  119. return false;
  120. }
  121. });
  122.  
  123. convert(holder, list.get(position), position, isScrolling);
  124.  
  125. }
  126.  
  127. @Override
  128. public int getItemCount() {
  129. return list == null ? 0 : list.size();
  130. }
  131.  
  132. public void setOnItemClickListener(OnItemClickListener listener) {
  133. this.listener = listener;
  134. }
  135.  
  136. public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
  137. this.longClickListener = longClickListener;
  138. }
  139.  
  140. /**
  141. * 填充RecyclerView适配器的方法,子类需要重写
  142. *
  143. * @param holder ViewHolder
  144. * @param item 子项
  145. * @param position 位置
  146. * @param isScrolling 是否在滑动
  147. */
  148. public abstract void convert(BaseRecyclerHolder holder, T item, int position, boolean isScrolling);
  149. }

注意其中我的抽象方法给了一个isScrolling的参数,我的目的是想控制滑动的时候不加载图片。目前这个还没实现,所以大家可以在自己封装的时候不去写它,当然,你有思考的话我建议大家最好实现吧,另外别忘了告诉楼主哦~~嘿嘿。楼主就是这样的谦(zhuang)虚(bi)。

其他的代码就很简单了,java bean类Data和布局和昨天一样的,大家可以自己去随便怎么布局。

这里只上一个MainActivity的代码,有需要的大家可以去github提取:https://github.com/nanchen2251/CommonAdapterRecyclerDemo

  1. package com.example.nanchen.commonadaperrecyclerdemo;
  2.  
  3. import android.os.Bundle;
  4. import android.support.v7.app.AppCompatActivity;
  5. import android.support.v7.widget.LinearLayoutManager;
  6. import android.support.v7.widget.RecyclerView;
  7. import android.view.View;
  8. import android.widget.EditText;
  9. import android.widget.Toast;
  10.  
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. import java.util.Locale;
  14.  
  15. public class MainActivity extends AppCompatActivity {
  16.  
  17. private List<Data> list;
  18. private RecyclerView recyclerView;
  19. private BaseRecyclerAdapter<Data> adapter;
  20. private EditText text;
  21.  
  22. @SuppressWarnings("unchecked")
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.activity_main);
  27.  
  28. list = new ArrayList<>();
  29.  
  30. initList();
  31.  
  32. adapter = new BaseRecyclerAdapter<Data>(this,list,R.layout.list_item) {
  33. @Override
  34. public void convert(BaseRecyclerHolder holder, Data item, int position, boolean isScrolling) {
  35. holder.setText(R.id.item_text,item.getText());
  36. if (item.getImageUrl() != null){
  37. holder.setImageByUrl(R.id.item_image,item.getImageUrl());
  38. }else {
  39. holder.setImageResource(R.id.item_image,item.getImageId());
  40. }
  41. }
  42.  
  43. };
  44.  
  45. adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
  46. @Override
  47. public void onItemClick(RecyclerView parent, final View view, int position) {
  48. Toast.makeText(MainActivity.this, String.format(Locale.CHINA,"你点击了第%d项,长按会删除!",position),Toast.LENGTH_SHORT).show();
  49. }
  50. });
  51.  
  52. adapter.setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
  53. @Override
  54. public boolean onItemLongClick(RecyclerView parent, View view, int position) {
  55. adapter.delete(position);
  56. return true;
  57. }
  58. });
  59.  
  60. text = (EditText) findViewById(R.id.main_text);
  61. recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
  62. recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
  63. recyclerView.setAdapter(adapter);
  64.  
  65. }
  66.  
  67. public void initList(){
  68. for (int i = 0; i < 5; i++) {
  69. list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
  70. }
  71. for (int i = 0; i < 5; i++) {
  72. list.add(new Data("网络 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
  73. }
  74. }
  75.  
  76. public void btnClick(View view) {
  77. String string = text.getText().toString().trim();
  78. Data data = new Data(string,R.mipmap.ic_launcher);
  79. // list.add(list.size()/2,data);
  80. adapter.insert(data,list.size()/2);
  81.  
  82. Toast.makeText(MainActivity.this,list.size()+"",Toast.LENGTH_SHORT).show();
  83. }
  84. }

打造android偷懒神器———RecyclerView的万能适配器的更多相关文章

  1. 打造android偷懒神器———ListView的万能适配器

    如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中.虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但 ...

  2. Android万能适配器Adapter-android学习之旅(74)

    万能适配器的代码的github地址是https://github.com/fengsehng/CommonAdapter 万能适配器的代码的github地址是https://github.com/fe ...

  3. 安卓开发笔记——打造万能适配器(Adapter)

    为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...

  4. 打造Android万能上拉下拉刷新框架--XRefreshView(三)

    转载请注明出处:http://blog.csdn.net/footballclub/ 打造Android万能上拉下拉刷新框架–XRefreshView(一) 打造Android万能上拉下拉刷新框架–X ...

  5. Android之ListView性能优化——一行代码绑定数据——万能适配器

    如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...

  6. Android进阶笔记10:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

  7. Android开发之万能适配器

    ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法 ...

  8. 打造android万能上拉下拉刷新框架——XRefreshView (二)

    打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下 ...

  9. Android进阶笔记09:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

随机推荐

  1. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  2. 标准产品+定制开发:专注打造企业OA、智慧政务云平台——山东森普软件,交付率最高的技术型软件公司

    一.公司简介山东森普信息技术有限公司(以下简称森普软件)是一家专门致力于移动互联网产品.企业管理软件定制开发的技术型企业.公司总部设在全国五大软件园之一的济南齐鲁软件园.森普SimPro是由Simpl ...

  3. HTML5 sessionStorage会话存储

    sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.本篇主要介绍 sessionStorage(会话存储) ...

  4. redux-undo

    简介 通过包装reducer,创建一个state History,保留历史state,可以做退一步,进一步操作 1.install npm install --save redux-undo@beta ...

  5. OpenCASCADE Job - dimue

  6. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示(补充)

    在2.1.栏目的前台显示中因右键没有添加视图把微软给鄙视了一下,后来有仔细研究了一下发现应该鄙视自己,其实这个功能是有的,是自己没搞清楚乱吐糟. 其实只要在NuGet中安装两个包(Microsoft. ...

  7. springMVC初探--环境搭建和第一个HelloWorld简单项目

    注:此篇为学习springMVC时,做的笔记整理. MVC框架要做哪些事情? a,将url映射到java类,或者java类的方法上 b,封装用户提交的数据 c,处理请求->调用相关的业务处理—& ...

  8. 文件随机读写专用类——RandomAccessFile

     RandomAccessFile类可以随机读取文件,但是在测试中并不好用;File类可以测试文件存不存在,不存在可以创建文件;FileWriter类可以对文件进行重写或者追加内容;FileReade ...

  9. 记录一次bug解决过程:数据迁移

    一 总结 不擅长语言表达,勤于沟通,多锻炼 调试MyBatis中SQL语法:foreach 问题:缺少关键字VALUES.很遗憾:它的错误报的让人找不着北. 二 BUG描述:MyBatis中批量插入数 ...

  10. 满堂红CIO邓劲翔:房屋中介突围

    人脸识别.客户关系管理进度监控.业务流程实时监控.网站访问人数及流量实时监控等实际企业应用场景淋漓尽致.羽羽如生的以大屏幕上图表形式展现在人们面前,如果你不去继续询问,你不会知道这是一家才刚刚在房地产 ...