打造android偷懒神器———RecyclerView的万能适配器
转载请注明出处谢谢: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的万能适配器的更多相关文章
- 打造android偷懒神器———ListView的万能适配器
如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中.虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但 ...
- Android万能适配器Adapter-android学习之旅(74)
万能适配器的代码的github地址是https://github.com/fengsehng/CommonAdapter 万能适配器的代码的github地址是https://github.com/fe ...
- 安卓开发笔记——打造万能适配器(Adapter)
为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...
- 打造Android万能上拉下拉刷新框架--XRefreshView(三)
转载请注明出处:http://blog.csdn.net/footballclub/ 打造Android万能上拉下拉刷新框架–XRefreshView(一) 打造Android万能上拉下拉刷新框架–X ...
- Android之ListView性能优化——一行代码绑定数据——万能适配器
如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...
- Android进阶笔记10:Android 万能适配器
1. Android 万能适配器 项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...
- Android开发之万能适配器
ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法 ...
- 打造android万能上拉下拉刷新框架——XRefreshView (二)
打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下 ...
- Android进阶笔记09:Android 万能适配器
1. Android 万能适配器 项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...
随机推荐
- ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”
在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...
- C# MVC 5 - 生命周期(应用程序生命周期&请求生命周期)
本文是根据网上的文章总结的. 1.介绍 本文讨论ASP.Net MVC框架MVC的请求生命周期. MVC有两个生命周期,一为应用程序生命周期,二为请求生命周期. 2.应用程序生命周期 应用程序生命周期 ...
- 几个比较”有意思“的JS脚本
1.获取内网和公网真实IP地址(引用地址) <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- DDD 领域驱动设计-商品建模之路
最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...
- 设计模式之行为类模式大PK
行为类模式大PK 行为类模式包括责任链模式.命令模式.解释器模式.迭代器模式.中介者模式.备忘录模式.观察者模式.状态模式.策略 ...
- javascript动画系列第二篇——磁性吸附
× 目录 [1]范围限定 [2]拖拽范围 [3]磁性吸附 前面的话 上一篇,我们介绍了元素拖拽的实现.但在实际应用中,常常需要为拖拽的元素限定范围.而通过限定范围,再增加一些辅助的措施,就可以实现磁性 ...
- Performance Monitor4:监控SQL Server的IO性能
SQL Server的IO性能受到物理Disk的IO延迟和SQL Server内部执行的IO操作的影响.在监控Disk性能时,最主要的度量值(metric)是IO延迟,IO延迟是指从Applicati ...
- bzoj3037--贪心
题目大意: applepi手里有一本书<创世纪>,里面记录了这样一个故事--上帝手中有着N 种被称作"世界元素"的东西,现在他要把它们中的一部分投放到一个新的空间中去以 ...
- APP多版本共存,服务端如何兼容?
做过APP产品的技术人员都知道,APP应用属于一种C/S架构的,所以在做多版本兼容,升级等处理则比较麻烦,不像web应用那么容易.下面将带大家分析几种常见的情况和应对方式: 小改动或者新加功能的 这种 ...