• 打造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();
        }
    }
  • 相关阅读:
    HDU_1846 Brave Game(sg函数简化版)
    POJ 3225 Help with Intervals(线段树)
    ZOJ_3501 Roman Order
    HDU_1527 取石子游戏(威佐夫博弈)
    HDU_2112 HDU Today(DIjkstra + map映射)
    HDU_3339 In Action(Dijkstra + DP)
    单链表的实现(课本上的算法)
    haproxy 基于 uri 实现调度
    haproxy 基于 cookie 实现 session 绑定
    [转]ASP.NET 虚拟主机安全漏洞解决方案
  • 原文地址:https://www.cnblogs.com/liushilin/p/5720926.html
Copyright © 2020-2023  润新知