偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder

前言

昨天开始接触江湖口碑很好的RecyclerView,事实上,我已经被她的强大所征服了!资源回收,数据绑定,布局显示,分割线,Item动画多个模块高度解耦,灵活优雅。其实,RecyclerView在使用上已经是相当简单了(个人觉得),但仍有很多代码是可以加以封装的。今天受简书上一篇博文的启发,作为写代码喜欢优(tou)雅(lan)的人,想到了一种封装方式,打造万能适配器,供大家食用。

正统模式:

public class SimplerItemAdapter extends RecyclerView.Adapter<SimplerItemAdapter.SimpleItemViewHolder > {    
    private List <String> items;  
    public SimplerItemAdapter (@NonNull List<String> dateItems ) {    this.items = (dateItems != null ? dateItems : new ArrayList<String>());   
    }    
    
    @Override 
    public SimpleItemViewHolder onCreateViewHolder (ViewGroup viewGroup, int viewType) {     
    View itemView = LayoutInflater.from( viewGroup.getContext ()).inflate(R.layout .item, viewGroup, false );    
    return new SimpleItemViewHolder(itemView);   
    }   
    
     @Override 
     public void onBindViewHolder (SimpleItemViewHolder viewHolder, int position) {     
     viewHolder.textView .setText(items.get (position));   
     }    
     
     @Override 
     public int getItemCount () {    
     return (this.items != null) ? this .items. size() : 0 ;   
     }  
     
     protected final static class SimpleItemViewHolder extends RecyclerView.ViewHolder {     
     protected TextView textView ;    
     public SimpleItemViewHolder (View itemView) {      
         super(itemView);      
         this.textView = (TextView) itemView.findViewById (R. id.text);     }   
     }     
}
  • 首先, @Override public int getItemCount () { return (this.items != null) ? this .items. size() : 0 ; }这段代码完全可以封装起来的。
  • onCreatedViewHolder()方法作用是绑定item视图,可以进一步封装,给子类提供一个getLayoutItemId的抽象方法,这样就可以简化成一行代码了。
  • 因此我们发现,这个adapter的核心代码在与onBindViewHolder()中,作用是将数据跟视图(ViewHolder)绑定,可以给子类提供一个bindData()抽象方法。
  • 当然了,使用泛型也是极好的,拓广了adapter的使用范围。
  • 添加点击事件的监听也可以封装到万能adapter中,子类就不用再写item点击事件处理代码了

封装后的Adapter

public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {    
    protected final List<T> mData;    
    protected final Context mContext;    
    protected LayoutInflater mInflater;    
    private OnItemClickListener mClickListener;    
    private OnItemLongClickListener mLongClickListener;    
    public BaseRecyclerAdapter(Context ctx, List<T> list) {               mData = (list != null) ? list : new ArrayList<T>();               mContext = ctx;         

        mInflater = LayoutInflater.from(ctx);     

    }      

    @Override    
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         

    final RecyclerViewHolder holder = new RecyclerViewHolder(mContext,                 

    mInflater.inflate(getItemLayoutId(viewType), parent, false));     if (mClickListener != null) {             

    holder.itemView.setOnClickListener(new View.OnClickListener() 

        @Override                

        public void onClick(View v) {                     

        mClickListener.onItemClick(holder.itemView, holder.getLayoutPosition());                 

        }             });         

    }        

    if (mLongClickListener != null) {             

    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {                 

    @Override                

    public boolean onLongClick(View v) {                     

    mLongClickListener.onItemLongClick(holder.itemView, holder.getLayoutPosition());                    

    return true;                 

        }             });         

    }        

    return holder;     
}      
    @Override    
    public void onBindViewHolder(RecyclerViewHolder holder, int position) {         

    bindData(holder, position, mData.get(position));     

    }      

    @Override    

    public int getItemCount() {        

    return mData.size();     

    }    

    public void add(int pos, T item) {         

    mData.add(pos, item);         

    notifyItemInserted(pos);     

    }    

    public void delete(int pos) {         

    mData.remove(pos);         

    notifyItemRemoved(pos);     

    }    

    public void setOnItemClickListener(OnItemClickListener listener) {         

    mClickListener = listener;     

    }    

    public void setOnItemLongClickListener(OnItemLongClickListener listener) {         

    mLongClickListener = listener;     

    }    

    abstract public int getItemLayoutId(int viewType);    

    abstract public void bindData(RecyclerViewHolder holder, int position, T item);    

    public interface OnItemClickListener {        

        public void onItemClick(View itemView, int pos);     

    }    

    public interface OnItemLongClickListener {        

        public void onItemLongClick(View itemView, int pos);     

    } 
}

Super ViewHolder

其实,这还没完呢!重头戏在ViewHolder上!RecyclerView强制我们使用ViewHolder模式,然而缺不可避免地要写findViewById代码,有没有办法不写这样的代码呢?甚至连ViewHolder都不写呢?当然可以!

public class RecyclerViewHolder extends RecyclerView.ViewHolder {     private SparseArray<View> mViews;     
    private Context mContext;      

    public RecyclerViewHolder(Context ctx, View itemView) {               super(itemView);         
        mContext = ctx;         
        mViews = new SparseArray<View>();     
    }    
    
    private <T extends View> T findViewById(int viewId) {                 View view = mViews.get(viewId);        
        if (view == null) {             
        view = itemView.findViewById(viewId);             
        mViews.put(viewId, view);         
        }        
        return (T) view;     
    }    
    
    public View getView(int viewId) {        
        return findViewById(viewId);     
    }    
    
    public TextView getTextView(int viewId) {        
        return (TextView) getView(viewId);     
    }    
    
    public Button getButton(int viewId) {        
        return (Button) getView(viewId);     
    }    
    
    public ImageView getImageView(int viewId) {        
        return (ImageView) getView(viewId);     
    }    
    
    public ImageButton getImageButton(int viewId) {        
        return (ImageButton) getView(viewId);     
    }    
    
    public EditText getEditText(int viewId) {        
        return (EditText) getView(viewId);     
    }    
    
    public RecyclerViewHolder setText(int viewId, String value) {         TextView view = findViewById(viewId);         
        view.setText(value);        
        return this;     
    }    
    
    public RecyclerViewHolder setBackground(int viewId, int resId) {         
        View view = findViewById(viewId);         
        view.setBackgroundResource(resId);        
        return this;     
    }    
    
    public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener) {         
        View view = findViewById(viewId);         
        view.setOnClickListener(listener);        
        return this;     } 
    }

该类的核心方法是private T findViewById(int viewId),核心成员变量是private SparseArray mViews; 不信可以不写一句ViewHolder代码?接下来看看用法。

实践用法

添加Adapter仅需短短的几行代码:

Adapter = new BaseRecyclerAdapter<String>(this,mDataList) {            @Override             
    public int getItemLayoutId(int viewType) {                
        return R.layout.item;             
    }            
    
    @Override             
    public void bindData(RecyclerViewHolder holder, int position,String item) {
     //调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可                          
        holder.setText(R.id.tv_num,item).getTextView(R.id.tv_title,item).setText(item);             
    }         
};

完整代码:

private void init() {         
    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);    mDataList = new ArrayList<>();        
    for (int i = 0; i <= 100; i++) {             
        mDataList.add(String.valueOf(i));         
    }       
     //设置item动画
    recyclerView.setItemAnimator(new DefaultItemAnimator());          mAdapter = new BaseRecyclerAdapter<String>(this,mDataList) {            
    @Override             
    public int getItemLayoutId(int viewType) {                
     
        return R.layout.item;             
     
    }            
    
     @Override             
     public void bindData(RecyclerViewHolder holder, int position,String item) {   
     
       //调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可             
         holder.setText(R.id.tv_num,item).getTextView(R.id.tv_title,item).setText(item);             
     }    
          
     };   
           
     recyclerView.setAdapter(mAdapter);     
       
     //添加item点击事件监听 
    ((BaseRecyclerAdapter)mAdapter).setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {  
               
     @Override             
     public void onItemClick(View itemView, int pos) {                     Toast.makeText(AdapterTestActivity.this, "click " + pos, Toast.LENGTH_SHORT).show();            
     
      }         
      });         
      
      ((BaseRecyclerAdapter)mAdapter).setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {  
                
      @Override             
      public void onItemLongClick(View itemView, int pos) {                 Toast.makeText(AdapterTestActivity.this, "long click " + pos, Toast.LENGTH_SHORT).show();             
      }   
            
      });
              
        //设置布局样式LayoutManager
      recyclerView.setLayoutManager(new LinearLayoutManager(AdapterTestActivity.this, LinearLayoutManager.VERTICAL, false));
      //        recyclerView.addItemDecoration(new ItemDividerDecoration(MainActivity.this, OrientationHelper.VERTICAL));
      }

如果觉得有什么不妥之处或建议,敬请指教! 完整项目代码已上传至Github(https://github.com/TellH/RecyclerViewDemo)。

原文发布于微信公众号 - 非著名程序员(non-famous-coder)

原文发表时间:2016-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

【插件开发】—— 6 SWT 复杂控件使用以及布局

前文回顾: 1 插件学习篇 2 简单的建立插件工程以及模型文件分析 3 利用扩展点,开发透视图 4 SWT编程须知 5 SWT简单控件的使用与布局搭...

2609
来自专栏Android开发指南

9.indicate、xutils、json

36813
来自专栏Android知识点总结

3-VI--☆ListView的封装

1162
来自专栏向治洪

android RecycleView Adapter简单封装

早些时候我们使用系统提供个的BaseAdapter的时候为了满足大家的需要,我们总会对BaseAdapter做一层上层的封装,然后对于实际业务我们只需要关心ge...

2808
来自专栏听雨堂

Android新手之旅(8) ListView的使用

  希望使用ListView来展示信息,每行一个图标,右侧是文字,分为两行布局。经过尝试,这样可以实现: 1、Layout下新建item.xml <?xml...

20110
来自专栏Android开发指南

Android自定义安全键盘

6839
来自专栏向治洪

解决ListView嵌套ListView遇到的问题

Listview嵌套会造成的问题主要是子listview的高度错误导致内容不能正常显示完,解决这个问题,我个人第一个想法就是重新计算子listview的高度,代...

1996
来自专栏向治洪

ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示(优化篇)

上一张效果图: ? ? ? 之前的项目有一个Galley的项目,但是代码结构特别乱,别问我为什么,我也是刚接手这个项目,为了方便以后阅读和维护我对一些模块进行了...

2919
来自专栏Android开发指南

通过代码定义shape/selector

3469
来自专栏听雨堂

Android新手之旅(8) ListView的使用

  希望使用ListView来展示信息,每行一个图标,右侧是文字,分为两行布局。经过尝试,这样可以实现: 1、Layout下新建item.xml <?xml...

2466

扫码关注云+社区