前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder

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

作者头像
非著名程序员
发布2018-02-02 14:48:08
1.4K0
发布2018-02-02 14:48:08
举报
文章被收录于专栏:非著名程序员

前言

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

正统模式:

代码语言:javascript
复制
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

代码语言:javascript
复制
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都不写呢?当然可以!

代码语言:javascript
复制
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仅需短短的几行代码:

代码语言:javascript
复制
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);             
    }         
};

完整代码:

代码语言:javascript
复制
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)。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 非著名程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正统模式:
  • 封装后的Adapter
  • Super ViewHolder
  • 实践用法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档