热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要给大家介绍了关于Android中封装RecyclerView实现添加头部和底部的相关资料,网上这方面的资料很多,但都不是自己需要的,索性自己写一个分享出来供大家参考学习,需要的朋友们下面随着小编一起来学习学习吧。

前言

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

首先看下实现的效果:


代码如下:

public class WrapMyRecyclerView extends RecyclerView {

 private Adapter mAdapter;
 private ArrayList mHeaderViewInfos = new ArrayList<>();//保存headerView
 private ArrayList 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 headerViewInfos,
   ArrayList 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 mHeaderViewInfos;//保存headerview数据
 private final ArrayList 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 headerViewInfos,
           ArrayList 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 

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

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

<&#63;xml version="1.0" encoding="utf-8"&#63;>


 

这是布局文件

public class WrapRecyclerViewActivity extends AppCompatActivity {
 private WrapMyRecyclerView mRecyclerView;
 private MyAdapter mMyAdapter;
 private List 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 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 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 &#63; 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开发者们的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何解决MyBatis中常见的BindingException错误,提供了多种排查和修复方法,确保Mapper接口与XML文件的正确配置。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
author-avatar
mobiledu2502912677
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有