打造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的封装,这个看起来我相信很好理解。

 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
112         holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
113             @Override
114             public boolean onLongClick(View view) {
115                 if (longClickListener != null && view != null && recyclerView != null) {
116                     int position = recyclerView.getChildAdapterPosition(view);
117                     longClickListener.onItemLongClick(recyclerView, view, position);
118                     return true;
119                 }
120                 return false;
121             }
122         });
123
124         convert(holder, list.get(position), position, isScrolling);
125
126     }
127
128     @Override
129     public int getItemCount() {
130         return list == null ? 0 : list.size();
131     }
132
133     public void setOnItemClickListener(OnItemClickListener listener) {
134         this.listener = listener;
135     }
136
137     public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
138         this.longClickListener = longClickListener;
139     }
140
141     /**
142      * 填充RecyclerView适配器的方法,子类需要重写
143      *
144      * @param holder      ViewHolder
145      * @param item        子项
146      * @param position    位置
147      * @param isScrolling 是否在滑动
148      */
149     public abstract void convert(BaseRecyclerHolder holder, T item, int position, boolean isScrolling);
150 }

注意其中我的抽象方法给了一个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();
    }
}
时间: 2024-07-31 14:26:17

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

RecyclerView的万能适配器+定义可以到底部自动刷新的RecyclerView

RecyclerView的重要性就不做重复说明了,为了方便以后直接使用写了这个,主要有: 万能适配器在使用的时候分为定义布局和绑定数据,方便直接套用.加入了底部刷新,需要配合自己写的RecyclerView一起使用,对于布局中各个子布局和控件可以做到响应各种点击事件: 首先抽取ViewHolder:这里的要点是用到了SparseArray(源码中类似ArrayList.直接使用Object数组进行实现): package com.fightzhao.baseadapterdemo.base; i

Android之ListView性能优化——万能适配器

如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有觉得有什么不好的.直到最近在慕课网上看到鸿洋大神讲的“机器人小慕”和“万能适配器”两节课,才对BaseAdapter有所了解.看了鸿洋大神的课程之后,我又上网搜了几个博客,也看了一些源码和文档,于是打算写一个帖子来记录一下自己的学习历程. 在今天的帖子中,我们从一个最基本的实现BaseAdapter

Android适配器之定义PagerAdapter万能适配器

一般使用pageAdapter需要实现getcount.isViewFromObject.instantiateItem.destroyItem等默认函数,其实完全可以抽取共有代码到父类当中. /** * Created by Xiaoxuan948 on 2015/10/27. * Desc: * 提示:先给adapter设置数据,再绑定适配器 setAdapter会调用instantiateItem方法 */public class AbsUnityBasePageAdapter<T> e

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

为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需要,因此我们时常要去继承BaseAdapter类去实现一个自定义的适配器来满足我们的场景需要. 如果你是开发一个简单点的APP还好,可能ListView和GridView的数量不会太多,我们只要去写几个BaseAdapter实现类就可以了. 但如果有一天,你需要开发一个APP里面具有几十个ListV

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

转载请注明出处:http://blog.csdn.net/footballclub/ 打造Android万能上拉下拉刷新框架–XRefreshView(一) 打造Android万能上拉下拉刷新框架–XRefreshView(二) XRefreshView更新说明 这段时间一直有朋友给我反馈,让我帮忙解决问题,我汇总了下,有以下几种: 1. 处理listview滑动删除与XRefreshView的冲突 2. 处理viewpager和XRefreshView的冲突 3. listview滑动到底部自

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

1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都需要去继承一个BaseAdapter,然后实现里面的一大堆方法,而我们每次最关心的无非就是getView方法,其余的方法几乎都是相同代码.这里是不是就可以优化起来呢?在其次,我们在使用Adapter的时候,为了优化性能,常常会创建一个Holder.而Holder里面每次存放的都是View,对Hole

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

打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下拉刷新框架--XRefreshView (一)之后,期间的大半个月一直都非常忙.可是我每天晚上下班以后都有在更新和维护XRefreshView,也依据一些朋友的意见攻克了一些问题,这次之所以写这篇文章.是由于XRefreshView已经到了一个功能相对可靠和稳定的一个阶段.以下我会介绍下Xrefre

Android开发之万能适配器

ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法和为什么要用? 这位博主写的非常好. http://www.cnblogs.com/lichenwei/p/4085107.html 所谓的万能适配器,无非是将适配器的重复代码抽取出来进行封装.不同功能的代码则留写一个方法留给用户复写,则每个listview的适配器就只变成几句话就够了. 这是一般适

RecyclerView万能适配器

转载请申明:http://blog.csdn.net/yoyo_newbie/article/details/48130813 没次当我们用RecyclerView是时候,不得不想到要添加点击事件, 头部,尾部,甚至分组繁琐代码烦恼,于是本人就无奈写了共用的adapter. 使用说明: 如,item资源为 R.layout.fragment_jiongtu_item_of_indexfregment item里面有个imageview id为 R.id.iv_photo private clas