万能的RecyclerViewAdapter,支持上拉加载、添加HeadView
来源:互联网 发布:影响一生的书籍知乎 编辑:程序博客网 时间:2024/06/05 09:25
最近的项目,使用RecyclerView比较多,导致需要写大量的Adapter和ViewHolder。不想偷懒的程序员不是好程序员。于是,查了一些资料,对RecyclerView的Adapter进行了一些封装。使用的时候减少了大量的工作。
先来点效果图
封装后的Adapter使用:
class DragSwipeAdapter extends BaseAdapter<String> { public DragSwipeAdapter(Context mContext, List<String> mDatas, int mLayoutId) { super(mContext, mDatas, mLayoutId); } @Override protected void convert(Context mContext, BaseViewHolder holder, String s) { holder.setText(R.id.tv,s); } }
只要传入数据源和item布局即可,是不是超级简单。
下面看看怎么实现的吧。
通用ViewHolder
package org.raphets.demorecyclerview.adapter;import android.annotation.SuppressLint;import android.graphics.Bitmap;import android.graphics.drawable.Drawable;import android.os.Build;import android.support.v7.widget.RecyclerView;import android.text.SpannableStringBuilder;import android.util.SparseArray;import android.view.View;import android.view.animation.AlphaAnimation;import android.widget.Checkable;import android.widget.ImageView;import android.widget.TextView;public class BaseViewHolder extends RecyclerView.ViewHolder { SparseArray<View> mViews; View mItemView; public BaseViewHolder(View itemView) { super(itemView); mItemView = itemView; mViews = new SparseArray<>(); } public <T extends View> T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mItemView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } public BaseViewHolder setText(int viewId, int resId) { TextView textView = getView(viewId); textView.setText(resId); return this; } public BaseViewHolder setText(int viewId, String text) { TextView textView = getView(viewId); textView.setText(text); return this; } public BaseViewHolder setText(int viewId, SpannableStringBuilder text) { TextView textView = getView(viewId); textView.setText(text); return this; } public BaseViewHolder setImageResource(int viewId, int resId) { ImageView view = getView(viewId); view.setImageResource(resId); return this; } public BaseViewHolder setImageBitmap(int viewId, Bitmap bitmap) { ImageView view = getView(viewId); view.setImageBitmap(bitmap); return this; } public BaseViewHolder setImageDrawable(int viewId, Drawable drawable) { ImageView view = getView(viewId); view.setImageDrawable(drawable); return this; } public BaseViewHolder setBackgroundColor(int viewId, int color) { View view = getView(viewId); view.setBackgroundColor(color); return this; } public BaseViewHolder setBackgroundResource(int viewId, int backgroundRes) { View view = getView(viewId); view.setBackgroundResource(backgroundRes); return this; } public BaseViewHolder setTextColor(int viewId, int textColor) { TextView view = getView(viewId); view.setTextColor(textColor); return this; } @SuppressLint("NewApi") public BaseViewHolder setAlpha(int viewId, float value) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { getView(viewId).setAlpha(value); } else { // Pre-honeycomb hack to set Alpha value AlphaAnimation alpha = new AlphaAnimation(value, value); alpha.setDuration(0); alpha.setFillAfter(true); getView(viewId).startAnimation(alpha); } return this; } public BaseViewHolder setVisible(int viewId, boolean visible) { View view = getView(viewId); view.setVisibility(visible ? View.VISIBLE : View.GONE); return this; } public BaseViewHolder setTag(int viewId, Object tag) { View view = getView(viewId); view.setTag(tag); return this; } public BaseViewHolder setTag(int viewId, int key, Object tag) { View view = getView(viewId); view.setTag(key, tag); return this; } public BaseViewHolder setChecked(int viewId, boolean checked) { Checkable view = (Checkable) getView(viewId); view.setChecked(checked); return this; } /** * 关于事件监听 */ public BaseViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = getView(viewId); view.setOnClickListener(listener); return this; } public BaseViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) { View view = getView(viewId); view.setOnTouchListener(listener); return this; } public BaseViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) { View view = getView(viewId); view.setOnLongClickListener(listener); return this; }}
这里对TextView、ImageView等常用控件的一些常用方法进行了封装。有了这个通用ViewHolder,再多的Adapter也只需要这一个ViewHolder,不用每写一个Adapter就要写一个ViewHolder。
通用Adapter
package org.raphets.demorecyclerview.adapter;import android.content.Context;import android.support.v7.util.DiffUtil;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import java.util.List;/** * Created by RaphetS on 2016/9/28. * 普通的万能Adapter * 支持onItemClick * 支持onLongItemClick */public abstract class BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder> { private Context mContext; private List<T> mDatas; private int mLayoutId; private OnItemClickListener mItemClickListener; private onLongItemClickListener mLongItemClickListener; public BaseAdapter(Context mContext, List<T> mDatas, int mLayoutId) { this.mContext = mContext; this.mDatas = mDatas; this.mLayoutId = mLayoutId; } public void updateData(List<T> data) { mDatas.clear(); mDatas.addAll(data); notifyDataSetChanged(); } public void addAll(List<T> data) { mDatas.addAll(data); notifyDataSetChanged(); } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false); BaseViewHolder holder = new BaseViewHolder(view); return holder; } @Override public int getItemCount() { return mDatas.size(); } @Override public void onBindViewHolder(BaseViewHolder holder, final int position) { convert(mContext, holder, mDatas.get(position)); if (mItemClickListener != null) { holder.mItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mItemClickListener.onItemClick(v, position); } }); } if (mLongItemClickListener != null) { holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mLongItemClickListener.onLongItemClick(v, position); return true; } }); } } protected abstract void convert(Context mContext, BaseViewHolder holder, T t); public interface OnItemClickListener { void onItemClick(View view, int position); } public interface onLongItemClickListener { void onLongItemClick(View view, int postion); } public void setOnItemClickListener(OnItemClickListener listener) { this.mItemClickListener = listener; } public void setonLongItemClickListener(onLongItemClickListener listener) { this.mLongItemClickListener = listener; }}
这里对RecyclerViewAdapter通用的地方封装了一下,然后封装了一下onItemClick和onLongItemClick事件。
如何使用
首先,写一个Adapter继承通用Adapter
class DragSwipeAdapter extends BaseAdapter<String> { public DragSwipeAdapter(Context mContext, List<String> mDatas, int mLayoutId) { super(mContext, mDatas, mLayoutId); } @Override protected void convert(Context mContext, BaseViewHolder holder, String s) { holder.setText(R.id.tv,s) .setTextColor(R.id.tv, Color.RED) .setImageResource(R.id.imageView,R.mipmap.ic_launcher); ImageView imageView=holder.getView(R.id.imageView); imageView.setImageResource(R.mipmap.ic_launcher); } }
代码比起原生的是不是少很多?
然后在Activity中使用即可。只要传入Context,数据源,item布局即可。
mAdapter = new DragSwipeAdapter(this, mData, R.layout.item); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(mAdapter);
是不是少了大量的工作。
但是貌似封装的还不够,我们的RecyclerView经常需要使用的功能还有下拉刷新,上拉加载,加个headview等等。下拉刷新好说,直接使用v4包里的SwipeRefreshLayout即可,上拉加载和HeadView怎么办呢?
下面我对上拉加载和HeadView也进行了一下封装。
(目前只支持LinearLayoutManager布局的RecyclerView)
首先ViewHoder不变,依然是上面的ViewHolder。
然后写了一个底部加载中的一个item布局。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:gravity="center" android:padding="20dp" android:layout_height="wrap_content"><ProgressBar style="@android:style/Widget.ProgressBar.Small" android:id="@+id/pb" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_marginLeft="10dp" android:text="正在加载..." android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>
下面是封装的Adapter
package org.raphets.demorecyclerview.adapter;import android.content.Context;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import org.raphets.demorecyclerview.R;import java.util.List;/** * Created by RaphetS on 2016/10/1. * 支持上拉加载 * 支持添加HeadView * 底部有进度条 */public abstract class BaseLoadMoreHeaderAdapter<T> extends RecyclerView.Adapter { private Context mContext; private boolean isLoading=false; private OnLoadMoreListener mOnLoadMoreListener; private OnItemClickListener mItemClickListener; private onLongItemClickListener mLongItemClickListener; private List<T> mDatas; private int mLayoutId; private View mHeadView; private final static int TYPE_HEADVIEW=100; private final static int TYPE_ITEM=101; private final static int TYPE_PROGRESS=102; public BaseLoadMoreHeaderAdapter(Context mContext, RecyclerView recyclerView, List<T> mDatas, int mLayoutId) { this.mContext = mContext; this.mDatas = mDatas; this.mLayoutId = mLayoutId; init(recyclerView); } private void init(RecyclerView recyclerView) { //mRecyclerView添加滑动事件监听 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int totalItemCount = linearLayoutManager.getItemCount(); int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); if (!isLoading &&dy>0&&lastVisibleItemPosition>=totalItemCount-1) { //此时是刷新状态 if (mOnLoadMoreListener != null) { mOnLoadMoreListener.onLoadMore(); } isLoading = true; } } }); } public void updateData(List<T> data) { mDatas.clear(); mDatas.addAll(data); notifyDataSetChanged(); } public void addAll(List<T> data) { mDatas.addAll(data); notifyDataSetChanged(); } public void addHeadView(View headView){ mHeadView=headView; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType==TYPE_ITEM){ View itemView= LayoutInflater.from(mContext).inflate(mLayoutId,parent,false); BaseViewHolder baseViewHolder=new BaseViewHolder(itemView); return baseViewHolder; }else if (viewType==TYPE_HEADVIEW){ HeadViewHolder headViewHolder=new HeadViewHolder(mHeadView); return headViewHolder; } else{ View progressView=LayoutInflater.from(mContext).inflate(R.layout.progress_item,parent,false); ProgressViewHolder progressViewHolder= new ProgressViewHolder(progressView); return progressViewHolder; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { if (holder instanceof BaseViewHolder){ convert(mContext, holder, mDatas.get(position)); ((BaseViewHolder) holder).mItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mItemClickListener.onItemClick(v,position-1); } }); ((BaseViewHolder) holder).mItemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mLongItemClickListener.onLongItemClick(v,position-1); return true; } }); } } @Override public int getItemViewType(int position) { if (mHeadView!=null){ if (position==getItemCount()-1){ return TYPE_PROGRESS; }else if (position==0){ return TYPE_HEADVIEW; }else { return TYPE_ITEM; } }else { if (position==getItemCount()-1){ return TYPE_PROGRESS; }else { return TYPE_ITEM; } } } public abstract void convert(Context mContext, RecyclerView.ViewHolder holder, T t); @Override public int getItemCount() { return mDatas.size()+1; } public void setLoading(boolean b){ isLoading=b; } public interface OnItemClickListener { void onItemClick(View view, int position); } public interface onLongItemClickListener { void onLongItemClick(View view, int postion); } public void setOnItemClickListener(OnItemClickListener listener) { this.mItemClickListener = listener; } public void setonLongItemClickListener(onLongItemClickListener listener) { this.mLongItemClickListener = listener; } public void setOnLoadMoreListener(OnLoadMoreListener listener){ this.mOnLoadMoreListener=listener; } public interface OnLoadMoreListener{ void onLoadMore(); } public class ProgressViewHolder extends RecyclerView.ViewHolder{ public ProgressViewHolder(View itemView) { super(itemView); } } public class HeadViewHolder extends RecyclerView.ViewHolder{ public HeadViewHolder(View itemView) { super(itemView); } }}
上拉加载和HeadView都是通过ItemViewType实现的,通过不同的position得到不同的ItemViewType,然后在onCreateViewHolder()的时候通过不同的ItemViewType加载不同的布局,创建不同的ViewHolder。
使用实例
1、首先写一个Adapter继承BaseLoadMoreHeaderAdapter,注意要判断holder的类型
class MyAdapter extends BaseLoadMoreHeaderAdapter<String> { public MyAdapter(Context mContext, RecyclerView recyclerView, List<String> mDatas, int mLayoutId) { super(mContext, recyclerView, mDatas, mLayoutId); } @Override public void convert(Context mContext, RecyclerView.ViewHolder holder, String s) { if (holder instanceof BaseViewHolder){ ((BaseViewHolder) holder).setText(R.id.tv,s); } } }
2、在Activity中设置Adapter
LinearLayoutManager layoutManager=new LinearLayoutManager(this); mAdapter=new MyAdapter(this,mRecyclerView,mDatas,R.layout.item); mRecyclerView.setLayoutManager(layoutManager); View headView= LayoutInflater.from(this).inflate(R.layout.headview,mRecyclerView,false); mAdapter.addHeadView(headView); mRecyclerView.setAdapter(mAdapter); mAdapter.setOnLoadMoreListener(new BaseLoadMoreHeaderAdapter.OnLoadMoreListener() { @Override public void onLoadMore() { loadMore(); } }); mAdapter.setOnItemClickListener(new BaseLoadMoreHeaderAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(getApplicationContext(),position+"",Toast.LENGTH_SHORT).show(); } });
注意这里,需要先给RecyclerView设置LayoutManager,在加载HeadView(View headView= LayoutInflater.from(this).inflate(R.layout.headview,mRecyclerView,false);)
否则会报错。
Demo地址
https://github.com/RaphetS/RecyclerView
原文链接:http://www.jianshu.com/p/8ca8bb6705e2
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
- 万能的RecyclerViewAdapter,支持上拉加载、添加HeadView
- XAdapter 一个支持 add 多个 header 和 footer,并且支持下拉刷新上拉加载的 recyclerViewAdapter
- 万能的RecyclerViewAdapter
- Android万能下拉刷新,上拉加载。支持自定义样式!!!
- 封装RecyclerViewAdapter实现RecyclerView下拉刷新上拉加载更多
- XAdapter:支持下拉刷新加载和添加多个header和footer的RecyclerViewAdapter
- 万能RecyclerViewAdapter
- 上拉加载的时候 添加数据
- 福利:打造一个万能的RecyclerViewAdapter
- 支持下拉刷新、上拉加载的RecyclerView,基于PullToRefresh
- 支持下拉刷新上拉加载xrecyclerview的基本使用
- 打造Android万能下拉刷新上拉加载控件
- 打造Android万能下拉刷新上拉加载控件
- 上拉加载下拉刷新的RecyclerView可添加headerView
- EasyRecyclerView 添加header,footer, 上拉加载更多的recyclerview
- RecyclerView添加footer实现上拉加载的自定义style
- 同事GITHUB上写的LISTVIEW下拉回弹 上拉HEADVIEW放大
- PullToRefreshListView添加headView的方法
- 第4章: zookeeper 基础API使用
- VS 2013 C++ 类模板定义与实现 进行分离
- jquery实例:让DIV移动到指定的位置标签后面
- oracle定时删除分区
- oracle数据库中为已经存在表的主键ID设置自增
- 万能的RecyclerViewAdapter,支持上拉加载、添加HeadView
- android NDK 编译 静态动态库
- 2组的项目计划
- Spring读书笔记-----使用Spring容器(二)
- 关于Unity与Android通信与交互
- EditBox
- LeetCode Longest Palindrome(计算最长的对称串)
- 单个或者多个jasper文件生成PDF文件
- 给大家分享一张CSS选择器优选级图谱 !