Android之工具通用的Adapter
在Android开发,特别是电商项目开发,使用RecyclerView、ListView、GridView是正常不过的了。一个项目下来,基本就是一直在写Adapter。刚开始写Adapter觉得没什么,无非就是ListView的继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式;RecyclerView的就继承 RecyclerView.Adapter,复写onCreateViewHolder、onBindViewHolder然后实现便完事。但当我写到10遍、100遍甚至更多的时候,我就不想写了,反正都是这种写法,也没什么新的套路。于是我就想写一个RecyclerView、ListView、GridView通用的Adapter。
在文章最后附上DEMO
项目运行的实际效果:左边是ListView,右边是RecyclerView。
二、常见ListView、RecyclerView Adapter写法的例子
代码没什么难度可以随便看看就好。
public class ListViewAdapter extends BaseAdapter { private LayoutInflater mInflater; private Context mContext; private List mDatas; private int mLayoutId; public ListViewAdapter(Context context, List mDatas,int layoutId) { mInflater = LayoutInflater.from(context); this.mContext = context; this.mDatas = mDatas; this.mLayoutId = layoutId; } @Override public int getCount() { return mDatas.size(); } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { convertView = mInflater.inflate(R.mLayoutId, parent, false); viewHolder = new ViewHolder(); viewHolder.mTextView = (TextView) convertView .findViewById(R.id.id_tv); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.mTextView.setText(mDatas.get(position)); return convertView; } private final class ViewHolder { TextView mTextView; } } private class RecyclerAdapter extends RecyclerView.Adapter { private LayoutInflater mInflater; private Context mContext; private List mData; private int mLayoutId; public RecyclerAdapter(Context context, List data, int layoutId) { mInflater = LayoutInflater.from(context); this.mContext = context; this.mData = data; this.mLayoutId = layoutId; } @Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(mLayoutId, parent, false); return new Holder(view); } @Override public void onBindViewHolder(Holder holder, int position) { holder.tv.setText(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } class Holder extends RecyclerView.ViewHolder { public TextView tv; public Holder(View itemView) { super(itemView); tv = itemView.findViewById(R.id.tv); } }}
三、ListView、RecyclerView Adapter一些共性分析
1. 要显示的条目个数2. 要显示和条目对应的类型3. ListView、RecyclerView中,总共有多少个条目类型4. 根据不同的条目类型加载不同的View5. ListView复用条目convertView,RecyclerView自带ViewHoler复用
四、抽取RecyclerView、ListView、GridView适配器的基类
由于要通用RecyclerView、ListView、GridView只能将RecyclerView.Adapter和ListAdapter,SpinnerAdapter
这些都给实现了。里面也没多少个方法,其实也是很简单。至于一些方法的实现我考贝BaseAdapter的实现,
大家可以去看看BaseAdapter的源码。
public class BaseAdapter extends RecyclerView.Adapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); // RecyclerView======================================================================== @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } // RecyclerView @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } // RecyclerView @Override public int getItemCount() { return 0; } // RecyclerView======================================================================== // ListView======================================================================== @Override public boolean areAllItemsEnabled() { return true; } @Override public boolean isEnabled(int position) { return true; } @Override public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } @Override public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } public void notifyListDataSetChanged() { mDataSetObservable.notifyChanged(); } @Override public Object getItem(int position) { return null; } @Override public View getView(int position, View convertView, ViewGroup parent) { return null; } @Override public int getViewTypeCount() { return 1; } @Override public int getItemViewType(int position) { return 0; } @Override public int getCount() { return 0; } @Override public boolean isEmpty() { return getCount() == 0; } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { return getView(position, convertView, parent); }}
五、抽取支持ListView、 GridView、 RecyclerView多条目的共性
public interface QuickMultiSupport { /** * 获取多条目View类型的数量 */ int getViewTypeCount(); /** * 根据数据,获取多条目布局ID */ int getLayoutId(T data); /** * 根据数据,获取多条目的ItemViewType */ int getItemViewType(T data); /** * 是否合并条目-->>使用RecyclerView时,如果无效,请用原生的RecyclerView */ boolean isSpan(T data);
六、打造RecyclerView、ListView、GridView通用的适配器
由于要同时适配RecyclerView、ListView、GridView,也就等于把两个Adapter的实现放在一个类里面
所以代码有点多,但代码我已分开,很容易看。
还有数据都复制出来的,条目的增删改查都在Adapter里面。
/** * RecyclerView、ListView、GridView通用的适配器 */public abstract class QuickAdapter extends BaseAdapter { private Context mContext; private List mData; private int mLayoutId; private QuickMultiSupport mSupport; private boolean isRecycler; private int mPosition; public QuickAdapter(Context context, List data, int layoutId) { this.mContext = context; this.mData = data == null ? new ArrayList() : new ArrayList(data); this.mLayoutId = layoutId; } public QuickAdapter(Context context, List data, QuickMultiSupport support) { this(context, data, 0); this.mSupport = support; } @Override public int getCount() { return mData.size(); } @Override public T getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { QuickViewHolder holder; if (convertView == null) { int layoutId = mLayoutId; // 多条目的 if (mSupport != null) { layoutId = mSupport.getLayoutId(mData.get(position)); } // 创建ViewHolder holder = createListHolder(parent, layoutId); } else { holder = (QuickViewHolder) convertView.getTag(); // 防止失误,还要判断 if (mSupport != null) { int layoutId = mSupport.getLayoutId(mData.get(position)); // 如果布局ID不一样,又重新创建 if (layoutId != holder.getLayoutId()) { // 创建ViewHolder holder = createListHolder(parent, layoutId); } } } // 绑定View的数据 convert(holder, mData.get(position), position); return holder.itemView; } /** * 创建ListView的Holer */ @NonNull private QuickViewHolder createListHolder(ViewGroup parent, int layoutId) { QuickViewHolder holder; View itemView = LayoutInflater.from(mContext).inflate(layoutId, parent, false); holder = new QuickViewHolder(itemView, layoutId); itemView.setTag(holder); return holder; } /** * ViewType的数量 */ @Override public int getViewTypeCount() { // 多条目的 if (mSupport != null) { return mSupport.getViewTypeCount() + super.getViewTypeCount(); } return super.getViewTypeCount(); } /** * 这个方法是共用的 */ @Override public int getItemViewType(int position) { mPosition = position; // 多条目的 if (mSupport != null) { return mSupport.getItemViewType(mData.get(position)); } return super.getItemViewType(position); } // RecyclerView================================================================================= @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { isRecycler = true; // 如果是多条目,viewType就是布局ID View view; if (mSupport != null) { int layoutId = mSupport.getLayoutId(mData.get(mPosition)); view = LayoutInflater.from(mContext).inflate(layoutId, parent, false); } else { view = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false); } QuickViewHolder holder = new QuickViewHolder(view); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof QuickViewHolder) { convert((QuickViewHolder) holder, mData.get(position), position); } } @Override public int getItemCount() { return mData.size(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { if (mSupport == null || recyclerView == null) { return; } RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); // 如果设置合并单元格就占用SpanCount那个多个位置 gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (mSupport.isSpan(mData.get(position))) { return gridLayoutManager.getSpanCount(); } else if (spanSizeLookup != null) { return spanSizeLookup.getSpanSize(position); } return 1; } }); gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount()); } } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { if (mSupport == null) { return; } int position = holder.getLayoutPosition(); // 如果设置合并单元格 if (mSupport.isSpan(mData.get(position))) { ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; p.setFullSpan(true); } } } // RecyclerView================================================================================= /** * 绑定View的数据 */ protected abstract void convert(QuickViewHolder holder, T item, int position); //==========================================数据相关================================================ public void add(T elem) { mData.add(elem); notifyData(); } public void addAll(List data) { mData.addAll(data); notifyData(); } public void addFirst(T elem) { mData.add(0, elem); notifyData(); } public void set(T oldElem, T newElem) { set(mData.indexOf(oldElem), newElem); notifyData(); } public void set(int index, T elem) { mData.set(index, elem); notify(); } public void remove(T elem) { mData.remove(elem); notifyData(); } public void remove(int index) { mData.remove(index); notifyData(); } public void replaceAll(List elem) { mData.clear(); mData.addAll(elem); notifyData(); } /** * 清除 */ public void clear() { mData.clear(); notifyData(); } private void notifyData() { if (isRecycler) { notifyDataSetChanged(); } else { notifyListDataSetChanged(); } } public List getData() { return mData; }}
七、通用ViewHolder的抽取
ViewHolder最主要就是实现平时常用的方法,比如:点击事件、长按事件、给TextView设置内容等等
如果不够,实际开发可以自己添加。
public class QuickViewHolder extends RecyclerView.ViewHolder { private SparseArray> mViews; private int mLayoutId; public QuickViewHolder(View itemView) { this(itemView, -1); } public QuickViewHolder(View itemView, int layoutId) { super(itemView); mViews = new SparseArray<>(); this.mLayoutId = layoutId; } public int getLayoutId() { return mLayoutId; } /** * 设置条目的点击事件 */ public QuickViewHolder setOnClickListener(View.OnClickListener listener) { itemView.setOnClickListener(listener); return this; } /** * 设置条目的长按事件 */ public QuickViewHolder setOnLongClickListener(View.OnLongClickListener listener) { itemView.setOnLongClickListener(listener); return this; } /** * 设置View的点击事件 * * @return */ public QuickViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = getView(viewId); if (view != null) { view.setOnClickListener(listener); } return this; } /** * 获取条目的View */ public View getView() { return itemView; } /** * 根据ID获取条目里面的View */ public T getView(int viewId) { WeakReference viewWeakReference = mViews.get(viewId); View view = null; if (viewWeakReference == null) { view = itemView.findViewById(viewId); if (view != null) { mViews.put(viewId, new WeakReference<>(view)); } } else { view = viewWeakReference.get(); } return (T) view; } public QuickViewHolder setText(int viewId, CharSequence text) { TextView tv = getView(viewId); if (tv != null && !TextUtils.isEmpty(text)) { tv.setText(text); } return this; } /** * 设置图片背景颜色 */ public QuickViewHolder setTextColor(int viewId, int color) { TextView view = getView(viewId); if (view != null) { view.setTextColor(color); } return this; } /** * 设置控件是否可见 */ public QuickViewHolder setVisible(int viewId, int visible) { View view = getView(viewId); view.setVisibility(visible); return this; } /** * 设置控件选中 */ public QuickViewHolder setChecked(int viewId, boolean checked) { Checkable view = getView(viewId); view.setChecked(checked); return this; } /** * 设置控件背景 */ public QuickViewHolder setBackgroundRes(int viewId, int backgroundRes) { View view = getView(viewId); view.setBackgroundResource(backgroundRes); return this; } /** * 设置图片 */ public QuickViewHolder setImageResource(int viewId, int imageResId) { ImageView imageView = getView(viewId); imageView.setImageResource(imageResId); return this; } /** * 设置图片 */ public QuickViewHolder setImageBitmap(int viewId, Bitmap bitmap) { ImageView imageView = getView(viewId); imageView.setImageBitmap(bitmap); return this; }}
八、项目实际使用
我只写了多条目的测试使用,对于一种类型的写法更为简单,我就不写了。
public class MainActivity extends AppCompatActivity { private List mData = new ArrayList<>(); private QuickMultiSupport mQuickSupport; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initViews(); } /** * 多条目的ViewType */ public interface IViewType { int getItemViewType(); } private void initData() { for (int i = 0; i < 199; i++) { if (i % 10 == 0) { MultiBean bean = new MultiBean(); bean.name = "mData--------" + i; mData.add(bean); } else { MultiBean1 bean = new MultiBean1(); bean.name = "mData--------" + i; mData.add(bean); } } // 多条目支持 mQuickSupport = new QuickMultiSupport() { // 条目总共两种类型 @Override public int getViewTypeCount() { return 2; } // 根据不用的JavaBean返回不同的布局 @Override public int getLayoutId(IViewType data) { if (data instanceof MultiBean) { return R.layout.item_list1; } return R.layout.item_list; } @Override public int getItemViewType(IViewType data) { return data.getItemViewType(); } @Override public boolean isSpan(IViewType data) { // 是否占用一个条目,针对RecyclerView if (data instanceof MultiBean) { return true; } return false; } }; } private void initViews() { ListView listView = findViewById(R.id.list_view); RecyclerView recyclerView = findViewById(R.id.recycler_view); // ListView设置Adapter listView.setAdapter(new CommAdapter(this, mData, mQuickSupport)); // RecyclerView设置Adapter recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); recyclerView.setAdapter(new CommAdapter(this, mData, mQuickSupport)); } class CommAdapter extends QuickAdapter { public CommAdapter(Context context, List data, int layoutId) { super(context, data, layoutId); } public CommAdapter(Context context, List data, QuickMultiSupport support) { super(context, data, support); } @Override protected void convert(QuickViewHolder holder, IViewType item, final int position) { holder.setText(R.id.tv, item.toString()); holder.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 点击移除当前条目 remove(position); } }); } }}
至此无论是RecyclerView还是ListView终于只用一个Adapter,
Demo下载
-END
更多相关文章
- TabLayout的使用及使用中的问题总结
- Android(安卓)开发知识点总结
- Android学习笔记——常用的基本UI组件及其常用属性值和相关方法
- 安卓Doubango架构的使用小结
- android 自定义radiobutton的样式 实现自己想要的样子
- 关于Android工程compilesdk,minsdk,targetsdk
- Android(安卓)Studio配置javah自动生成头文件
- Android中自定义Adapter的基本原理
- 解决listview设置背景图片以后,拖动出现黑色的问题。