首页 > 系统 > Android > 正文

Android中封装RecyclerView实现添加头部和底部示例代码

2019-12-12 02:12:09
字体:
来源:转载
供稿:网友

前言

我们大家都知道ListView具有添加头部和添加底部的方法,但是RecyclerView并没有这样子的方法。所以RecyclerView是不能添加底部和头部的,但是能不能仿造ListView来实现RecyclerView添加头部和底部呢?答案当然是可行的。本文就来给大家介绍了关于Android封装RecyclerView添加头部和底部的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

首先看下实现的效果:


代码如下:

public class WrapMyRecyclerView extends RecyclerView { private Adapter mAdapter; private ArrayList<View> mHeaderViewInfos = new ArrayList<>();//保存headerView private ArrayList<View> mFooterViewInfos = new ArrayList<>();//保存footerView public WrapMyRecyclerView(Context context) {  super(context); } public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs) {  super(context, attrs); } public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle); } /**  * 添加headerView  * @param v  */ public void addHeaderView(View v) {  mHeaderViewInfos.add(v);  // Wrap the adapter if it wasn't already wrapped.  if (mAdapter != null) {   if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) {    wrapHeaderListAdapterInternal();   }  } } /**  * 添加一个footerView  * @param v  */ public void addFooterView(View v) {  mFooterViewInfos.add(v);  // Wrap the adapter if it wasn't already wrapped.  if (mAdapter != null) {   if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) {    wrapHeaderListAdapterInternal();   }  } } /**  * 设置一个Adapter  * @param adapter  */ @Override public void setAdapter(Adapter adapter) {  if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {   mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);  } else {   mAdapter = adapter;  }  super.setAdapter(mAdapter); } private void wrapHeaderListAdapterInternal() {  mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter); } /**  * 新建一个RecyclerHeaderViewListAdapter对象  * 最终的adapter实现它  * @param headerViewInfos  * @param footerViewInfos  * @param adapter  * @return  */ protected RecyclerHeaderViewListAdapter wrapHeaderListAdapterInternal(   ArrayList<View> headerViewInfos,   ArrayList<View> footerViewInfos,   Adapter adapter) {  return new RecyclerHeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter); }}

这就是封装的RecyclerView,里面主要有三个方法addHeaderView、 addFooterView和重写的setAdapter。这里的唯一的思想就是偷梁换柱,当我们添加头部、尾部或者设置adapter时,真正的adapter并不是我们传入的adapter,而是重新new 了一个RecyclerHeaderViewListAdapter。这才是RecyclerView最终设置的adapter。

其实我们看到ListView也是通过这样子的思想来添加头部和尾部的。


这就是ListView的addHeaderView方法,它会偷偷的创建HeaderViewListAdapter这个adapter。最终添加的header和footer在HeaderViewListAdapter里面实现。

public class RecyclerHeaderViewListAdapter extends RecyclerView.Adapter { private final ArrayList<View> mHeaderViewInfos;//保存headerview数据 private final ArrayList<View> mFooterViewInfos;//保存footerView数据 private RecyclerView.Adapter mAdapter;   //用户自己构造的adapter private static final int RECYCLER_HEADER_VIEW = 0x001;//headerview类型 private static final int RECYCLER_FOOTER_VIEW = 0x002;//footerView类型 /**  * 构造方法  * 初始化  * @param headerViewInfos  * @param footerViewInfos  * @param adapter  */ public RecyclerHeaderViewListAdapter(ArrayList<View> headerViewInfos,           ArrayList<View> footerViewInfos,           RecyclerView.Adapter adapter) {  mAdapter = adapter;  if (headerViewInfos == null) {   mHeaderViewInfos = new ArrayList<>();  } else {   mHeaderViewInfos = headerViewInfos;  }  if (footerViewInfos == null) {   mFooterViewInfos = new ArrayList<>();  } else {   mFooterViewInfos = footerViewInfos;  } } /**  * 根据getItemViewType返回的条目类型  * 创建不同的itemview  * 传入的adapter,回调它的onCreateViewHolder即可  * @param parent  * @param viewType  * @return  */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  if (viewType == RECYCLER_HEADER_VIEW){   return new HeaderViewLayout(mHeaderViewInfos.get(0));  }else if (viewType == RECYCLER_FOOTER_VIEW){   return new HeaderViewLayout(mFooterViewInfos.get(0));  }  return mAdapter.onCreateViewHolder(parent,viewType); } /**  * 绑定数据  * headerview和footerview不需要绑定数据,直接return即可  * 传入的adapter需要回调它的onBindViewHolder即可  * @param holder  * @param position  */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {  //header  int numHeaders = getHeadersCount();  if (position < numHeaders) {   return ;  }  //adapter body  final int adjPosition = position - numHeaders;  int adapterCount = 0;  if (mAdapter != null) {   adapterCount = mAdapter.getItemCount();   if (adjPosition < adapterCount) {    mAdapter.onBindViewHolder(holder, adjPosition);    return ;   }  }  //footer } /**  * 返回条目的类型  * 传入的adapter,回调它的getItemViewType即可  * @param position  * @return  */ @Override public int getItemViewType(int position) {  // Header  int numHeaders = getHeadersCount();  if (position < numHeaders) {   return RECYCLER_HEADER_VIEW;  }  // Adapter  final int adjPosition = position - numHeaders;  int adapterCount = 0;  if (mAdapter != null) {   adapterCount = mAdapter.getItemCount();   if (adjPosition < adapterCount) {    return mAdapter.getItemViewType(position);   }  }  // Footer (off-limits positions will throw an IndexOutOfBoundsException)  return RECYCLER_FOOTER_VIEW; } /**  * 总条目即:footerview的条目+headerview的条目+穿入的adapter条目  * @return  */ @Override public int getItemCount() {  if (mAdapter != null) {   return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();  } else {   return getFootersCount() + getHeadersCount();  } } /**  * 获取headerview的条目  * @return  */ public int getHeadersCount() {  return mHeaderViewInfos.size(); } /**  * 获取footervie的条目  * @return  */ public int getFootersCount() {  return mFooterViewInfos.size(); } /**  * 这是footerview和headerview的ViewHolder需要  * 这里只是提供一个构造器即可,实际上用处不大  */ private static class HeaderViewLayout extends RecyclerView.ViewHolder{  public HeaderViewLayout(View itemView) {   super(itemView);  } }}

这是实现添加header、footer和传入adapter的RecyclerHeaderViewListAdapter。具体的逻辑都在文件的注释里面有说明。逻辑是仿造ListView的HeaderViewListAdapter来实现的。

其实就是创建一个adapter,然后根据不同的条目类型来创建条目和绑定条目的数据即可。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.wrap.recycler.WrapRecyclerViewActivity"> <com.lwj.wrap.recycler.WrapMyRecyclerView  android:id="@+id/wrap_recyclerview"  android:layout_width="match_parent"  android:layout_height="match_parent"/></LinearLayout>

这是布局文件

public class WrapRecyclerViewActivity extends AppCompatActivity { private WrapMyRecyclerView mRecyclerView; private MyAdapter mMyAdapter; private List<String> mList01 = new ArrayList<>(); private static final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_wrap_recycler_view);  getData();  mRecyclerView = (WrapMyRecyclerView) this.findViewById(R.id.wrap_recyclerview);  mRecyclerView.setLayoutManager(new LinearLayoutManager(this));  //加入headerView  ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(WC,WC);  ImageView headerView = new ImageView(this);  headerView.setImageResource(R.drawable.timg);  headerView.setLayoutParams(params);  mRecyclerView.addHeaderView(headerView);  //设置adapter  mMyAdapter = new MyAdapter(this,mList01);  mRecyclerView.setAdapter(mMyAdapter);  //加入footerView  params = new ViewGroup.LayoutParams(WC,WC);  ImageView footerView = new ImageView(this);  footerView.setImageResource(R.drawable.hhfj);  footerView.setLayoutParams(params);  mRecyclerView.addFooterView(footerView);  mMyAdapter.notifyDataSetChanged(); } public void getData() {  for (int i = 0; i < 3; i++) {   String data ="adapter...." + i;   mList01.add(data);  } }}

使用直接调用addHeaderView、addFooterView即可。

除了这种方式来实现addHeaderView和addFooterView,另外一种方式就是封装Adapter来实现,原理还是保持不变:根据不同的条目类型来创建条目和绑定条目的数据。

public class MyCircleRecycViewAdapter extends RecyclerView.Adapter { public List<CircleInfo.CirclePageInfo> infos = null; private Context mContext; private ListViewImgLoader mLoader; private View VIEW_FOOTER;//尾部 private View VIEW_HEADER;//头部 //Type private int TYPE_NORMAL = 1000; private int TYPE_HEADER = 1001; private int TYPE_FOOTER = 1002; private int tagType = TYPE_NORMAL; public MyCircleRecycViewAdapter(Context context,List<CircleInfo.CirclePageInfo> datas) {  this.infos = datas;  this.mContext = context;  mLoader = new ListViewImgLoader();  mLoader.setMemoryCacheSize(1024 * 1024);  mLoader.setVisibleItemCount(12); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  if (viewType == TYPE_FOOTER) {   tagType = TYPE_FOOTER;   return new MyCircleItemHolder(VIEW_FOOTER);  } else if (viewType == TYPE_HEADER) {   tagType = TYPE_HEADER;   return new MyCircleItemHolder(VIEW_HEADER);  } else {   tagType = TYPE_NORMAL;   View view = LayoutInflater.from(mContext).inflate(R.layout.circle_gridview_items, parent,false);   return new MyCircleItemHolder(view);  } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {  if (!isHeaderView(position) && !isFooterView(position)) {   if (haveHeaderView()) position--;   MyCircleItemHolder viewHolder = (MyCircleItemHolder)holder;   CircleInfo.CirclePageInfo mInfo = infos.get(position);   setData(viewHolder,mInfo);  } } @Override public int getItemCount() {  int count = (infos == null ? 0 : infos.size());  if (VIEW_FOOTER != null) {   count++;  }  if (VIEW_HEADER != null) {   count++;  }  return count; } @Override public int getItemViewType(int position) {  if (isHeaderView(position)) {   return TYPE_HEADER;  } else if (isFooterView(position)) {   return TYPE_FOOTER;  } else {   return TYPE_NORMAL;  } } public void addHeaderView(View headerView) {  if (haveHeaderView()) {   throw new IllegalStateException("hearview has already exists!");  } else {   //避免出现宽度自适应   ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(Utils.getRealPixel(30), Utils.getRealPixel(230));   headerView.setLayoutParams(params);   VIEW_HEADER = headerView;   notifyItemInserted(0);  } } public void addFooterView(View footerView) {  if (haveFooterView()) {   throw new IllegalStateException("footerView has already exists!");  } else {   ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);   footerView.setLayoutParams(params);   VIEW_FOOTER = footerView;//   ifGridLayoutManager();   notifyItemInserted(getItemCount() - 1);  } } private boolean haveHeaderView() {  return VIEW_HEADER != null; } public boolean haveFooterView() {  return VIEW_FOOTER != null; } private boolean isHeaderView(int position) {  return haveHeaderView() && position == 0; } private boolean isFooterView(int position) {  return haveFooterView() && position == getItemCount() - 1; } private void setData(final MyCircleItemHolder viewHolder, final CircleInfo.CirclePageInfo mInfo) {  if(mInfo == null || mInfo == viewHolder.tagInfo)  {   return;  }else{   viewHolder.tagInfo = mInfo;   if(!StrUtils.isEnpty(mInfo.thread_unread)){    if(mInfo.thread_unread.equals("0")){     viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE);    }else{     viewHolder.threaduUnreadTv.setVisibility(View.VISIBLE);     viewHolder.threaduUnreadTv.setText(mInfo.thread_unread);    }   }else{    viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE);   }   if (!TextUtils.isEmpty(viewHolder.tagUrl)){    if(mInfo.circle_img_path != null && !(mInfo.circle_img_path.equals(viewHolder.tagUrl))){     setImage(viewHolder.mImageView,mInfo.circle_img_path);    }   }else{    setImage(viewHolder.mImageView,mInfo.circle_img_path);   }   if (!TextUtils.isEmpty(mInfo.circle_img_path)){    viewHolder.tagUrl = mInfo.circle_img_path;   }   if(mInfo.circleName != null){    if(mInfo.circleName.length() > 5){     String s = mInfo.circleName.substring(0,5) + "...";     viewHolder.textView.setText(s);    }else{     viewHolder.textView.setText(mInfo.circleName);    }   }  } } private void setImage(final ColorFilterImageView mImageView, final String imgUrl){  mImageView.setBackgroundColor(0xffadadad);  mImageView.setImageBitmap(null);  if(!TextUtils.isEmpty(imgUrl))  {   mLoader.loadImage(mImageView.hashCode(), imgUrl, 300, new DnImg.OnDnImgListener()   {    @Override    public void onProgress(String url, int downloadedSize, int totalSize)    {     // TODO Auto-generated method stub    }    @Override    public void onFinish(String url, String file, Bitmap bmp)    {     if(url.equals(imgUrl))     {      mImageView.setImageBitmap(bmp);     }    }   });  }else{   mImageView.setBackgroundColor(0xffadadad);   mImageView.setImageBitmap(null);  } } class MyCircleItemHolder extends RecyclerView.ViewHolder{  private ColorFilterImageView mImageView;  private TextView textView;  private CircleInfo.CirclePageInfo tagInfo;  private String tagUrl;  private TextView threaduUnreadTv;  public MyCircleItemHolder(final View itemView) {   super(itemView);   if(tagType == TYPE_NORMAL){    mImageView = (ColorFilterImageView)itemView.findViewById(R.id.quan_icon);    mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);    textView = (TextView)itemView.findViewById(R.id.quan_name);    threaduUnreadTv = (TextView)itemView.findViewById(R.id.quan_num);    mImageView.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {      if (mListener != null){       mListener.oncliItem(itemView,tagInfo,threaduUnreadTv);      }     }    });   }  } } public OnclickMyCircleItemListener mListener; public void setOnclickMyCircleItemListener(OnclickMyCircleItemListener l){  this.mListener = l; } public interface OnclickMyCircleItemListener{  void oncliItem(View view,CircleInfo.CirclePageInfo info,View threadNumTv); } public void pauseLoader(){  if(mLoader != null)  {   mLoader.pause();  } } public void resumeLoader(){  if(mLoader != null)  {   mLoader.resume();  } } public void closeLoader(){  if(mLoader != null)  {   mLoader.close();  } }}

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对武林网的支持。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表