转载请注明出处谢谢: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的封装,这个看起来我相信很好理解。

 package com.example.nanchen.commonadaperrecyclerdemo;

 import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import com.squareup.picasso.Picasso; /**
* 万能的RecyclerView的ViewHolder
* Created by 南尘 on 16-7-30.
*/
public class BaseRecyclerHolder extends RecyclerView.ViewHolder { private SparseArray<View> views;
private Context context; private BaseRecyclerHolder(Context context,View itemView) {
super(itemView);
this.context = context;
//指定一个初始为8
views = new SparseArray<>(8);
} /**
* 取得一个RecyclerHolder对象
* @param context 上下文
* @param itemView 子项
* @return 返回一个RecyclerHolder对象
*/
public static BaseRecyclerHolder getRecyclerHolder(Context context,View itemView){
return new BaseRecyclerHolder(context,itemView);
} public SparseArray<View> getViews(){
return this.views;
} /**
* 通过view的id获取对应的控件,如果没有则加入views中
* @param viewId 控件的id
* @return 返回一个控件
*/
@SuppressWarnings("unchecked")
public <T extends View> T getView(int viewId){
View view = views.get(viewId);
if (view == null ){
view = itemView.findViewById(viewId);
views.put(viewId,view);
}
return (T) view;
} /**
* 设置字符串
*/
public BaseRecyclerHolder setText(int viewId,String text){
TextView tv = getView(viewId);
tv.setText(text);
return this;
} /**
* 设置图片
*/
public BaseRecyclerHolder setImageResource(int viewId,int drawableId){
ImageView iv = getView(viewId);
iv.setImageResource(drawableId);
return this;
} /**
* 设置图片
*/
public BaseRecyclerHolder setImageBitmap(int viewId, Bitmap bitmap){
ImageView iv = getView(viewId);
iv.setImageBitmap(bitmap);
return this;
} /**
* 设置图片
*/
public BaseRecyclerHolder setImageByUrl(int viewId,String url){
Picasso.with(context).load(url).into((ImageView) getView(viewId));
// ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
// ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
return this;
}
}

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

下面这些值得你注意:

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

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

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

还是直接看源码吧。

 package com.example.nanchen.commonadaperrecyclerdemo;

 import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; import java.util.List; /**
* 万能的RecyclerView适配器
* Created by 南尘 on 16-7-30.
*/
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerHolder> { private Context context;//上下文
private List<T> list;//数据源
private LayoutInflater inflater;//布局器
private int itemLayoutId;//布局id
private boolean isScrolling;//是否在滚动
private OnItemClickListener listener;//点击事件监听器
private OnItemLongClickListener longClickListener;//长按监听器
private RecyclerView recyclerView; //在RecyclerView提供数据的时候调用
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
} @Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
this.recyclerView = null;
} /**
* 定义一个点击事件接口回调
*/
public interface OnItemClickListener {
void onItemClick(RecyclerView parent, View view, int position);
} public interface OnItemLongClickListener {
boolean onItemLongClick(RecyclerView parent, View view, int position);
} /**
* 插入一项
*
* @param item
* @param position
*/
public void insert(T item, int position) {
list.add(position, item);
notifyItemInserted(position);
} /**
* 删除一项
*
* @param position 删除位置
*/
public void delete(int position) {
list.remove(position);
notifyItemRemoved(position);
} public BaseRecyclerAdapter(Context context, List<T> list, int itemLayoutId) {
this.context = context;
this.list = list;
this.itemLayoutId = itemLayoutId;
inflater = LayoutInflater.from(context); // recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
// @Override
// public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
// super.onScrollStateChanged(recyclerView, newState);
// isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE);
// if (!isScrolling) {
// notifyDataSetChanged();
// }
// }
// });
} @Override
public BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(itemLayoutId, parent, false);
return BaseRecyclerHolder.getRecyclerHolder(context, view);
} @Override
public void onBindViewHolder(final BaseRecyclerHolder holder, int position) { if (listener != null){
holder.itemView.setBackgroundResource(R.drawable.recycler_bg);//设置背景
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null && view != null && recyclerView != null) {
int position = recyclerView.getChildAdapterPosition(view);
listener.onItemClick(recyclerView, view, position);
}
}
}); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (longClickListener != null && view != null && recyclerView != null) {
int position = recyclerView.getChildAdapterPosition(view);
longClickListener.onItemLongClick(recyclerView, view, position);
return true;
}
return false;
}
}); convert(holder, list.get(position), position, isScrolling); } @Override
public int getItemCount() {
return list == null ? 0 : list.size();
} public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
} public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
this.longClickListener = longClickListener;
} /**
* 填充RecyclerView适配器的方法,子类需要重写
*
* @param holder ViewHolder
* @param item 子项
* @param position 位置
* @param isScrolling 是否在滑动
*/
public abstract void convert(BaseRecyclerHolder holder, T item, int position, boolean isScrolling);
}

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

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

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

package com.example.nanchen.commonadaperrecyclerdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List;
import java.util.Locale; public class MainActivity extends AppCompatActivity { private List<Data> list;
private RecyclerView recyclerView;
private BaseRecyclerAdapter<Data> adapter;
private EditText text; @SuppressWarnings("unchecked")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); list = new ArrayList<>(); initList(); adapter = new BaseRecyclerAdapter<Data>(this,list,R.layout.list_item) {
@Override
public void convert(BaseRecyclerHolder holder, Data item, int position, boolean isScrolling) {
holder.setText(R.id.item_text,item.getText());
if (item.getImageUrl() != null){
holder.setImageByUrl(R.id.item_image,item.getImageUrl());
}else {
holder.setImageResource(R.id.item_image,item.getImageId());
}
} }; adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(RecyclerView parent, final View view, int position) {
Toast.makeText(MainActivity.this, String.format(Locale.CHINA,"你点击了第%d项,长按会删除!",position),Toast.LENGTH_SHORT).show();
}
}); adapter.setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(RecyclerView parent, View view, int position) {
adapter.delete(position);
return true;
}
}); text = (EditText) findViewById(R.id.main_text);
recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
recyclerView.setAdapter(adapter); } public void initList(){
for (int i = 0; i < 5; i++) {
list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
}
for (int i = 0; i < 5; i++) {
list.add(new Data("网络 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
}
} public void btnClick(View view) {
String string = text.getText().toString().trim();
Data data = new Data(string,R.mipmap.ic_launcher);
// list.add(list.size()/2,data);
adapter.insert(data,list.size()/2); Toast.makeText(MainActivity.this,list.size()+"",Toast.LENGTH_SHORT).show();
}
}

打造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. 使用struct处理二进制

    有的时候需要用python处理二进制数据,比如,存取文件.socket操作时.这时候,可以使用python的struct模块来完成. struct模块中最重要的三个函数是pack(), unpack( ...

  2. vmware里面的名词 vSphere、vCenter Server、ESXI、vSphere Client

    vmware里面的名词 vSphere.vCenter Server.ESXI.vSphere Client vSphere.vCenter Server.ESXI.vSphere Client VS ...

  3. ABP文档 - EntityFramework 集成

    文档目录 本节内容: Nuget 包 DbContext 仓储 默认仓储 自定义仓储 特定的仓储基类 自定义仓储示例 仓储最佳实践 ABP可使用任何ORM框架,它已经内置了EntityFrame(以下 ...

  4. android 使用Tabhost 发生could not create tab content because could not find view with id 错误

    使用Tabhost的时候经常报:could not create tab content because could not find view with id 错误. 总结一下发生错误的原因,一般的 ...

  5. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager

    让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

  6. springmvc SSM shiro redis 后台框架 多数据源 代码生成器

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  7. Android 扫描条形码(Zxing插件)

    使用Android Studio 一.在build.gradle(Module:app)添加代码  下载,调用插件 1 apply plugin: 'com.android.application' ...

  8. Android中实现APP文本内容的分享发送与接收方法简述

    谨记(指定选择器Intent.createChooser()) 开始今天的内容前,先闲聊一下: (1)突然有一天头脑风暴,对很多问题有了新的看法和见解,迫不及待的想要分享给大家,文档已经写好了,我需要 ...

  9. Windows cmd 长时间不输出新内容 直到按下ctrl + c 取消或者回车的解决办法

    换了一台新电脑, 在使用 ant 拷贝大量文件的时候 cmd 窗口过了很久没有继续输出新的内容,远远超过平时的耗时, 以为已经卡死 按下 ctrl + c 取消, 这时并没有取消, 而是输出了新内容, ...

  10. 嵌入式C语言代码的调试技巧

    在项目开发的过程中,不可避免的会遇到调试代码的情况. 刚开始写代码时,我们想看具体执行到哪儿时,往往这么写: printf("***** Code is here! *****\n" ...