偷懒新姿势,打造属于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;//集合类,layout里包含的View,以view的id作为key,value是view对象
    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。—Github跳转

see also:
Listview的Adapter应该这样写

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
当我们使用RecyclerView来展示数据时,需要一个Adapter来处理数据和视图之间的交互。Adapter中的ViewHolder和onBindViewHolder是两个很重要的方法。 ViewHolder是RecyclerView用来缓存Item View和它们的子View的对象,这样可以避免重复查找和创建View,从而提高性能。我们需要在Adapter中定义一个ViewHolder类,继承RecyclerView.ViewHolder,并在其中声明需要缓存的View。 onBindViewHolder是RecyclerView在绑定数据时调用的方法,它的作用是将数据绑定到ViewHolder中缓存的View上。在Adapter中,我们需要重写这个方法,将数据和ViewHolder中的View绑定起来。 具体实现步骤如下: 1. 在Adapter中定义ViewHolder类,并在其中声明需要缓存的View。 ``` public class MyViewHolder extends RecyclerView.ViewHolder { public TextView title; public ImageView thumbnail; public MyViewHolder(View itemView) { super(itemView); title = itemView.findViewById(R.id.title); thumbnail = itemView.findViewById(R.id.thumbnail); } } ``` 2. 在Adapter中重写onCreateViewHolder方法,创建ViewHolder并返回。 ``` @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_layout, parent, false); return new MyViewHolder(itemView); } ``` 3. 在Adapter中重写onBindViewHolder方法,将数据绑定到ViewHolder中的View上。 ``` @Override public void onBindViewHolder(MyViewHolder holder, int position) { // 获取当前位置的数据 Data data = dataList.get(position); // 将数据绑定到ViewHolder中的View上 holder.title.setText(data.getTitle()); holder.thumbnail.setImageResource(data.getThumbnail()); } ``` 这样,我们就可以使用ViewHolder和onBindViewHolder来高效地展示数据了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值