RecyclerView添加头部和底部视图的实现

ListView是有addHeaderView和 addFooterView两个方法的.

但是作为官方推荐的ListView的升级版RecyclerView缺无法实现这两个方法。

那么如果使用RecyclerView实现这两个方法的效果该怎么做呢?

网上查询了很久,试过各种各样的实现方式,终于让我发现一个还不错的实现方法,那么就给大家推荐一下。

项目地址(别人写的,非博主的)https://github.com/jczmdeveloper/XCRecyclerView

我看了下这个源码,很简单,即写了一个继承RecyclerView的控件,自己实现addHeaderView和addFooterView两个方法

package com.xqx.com.recyclerviewheaderdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class XCRecyclerView extends RecyclerView{

    private ArrayList<View> mHeaderViews = new ArrayList<>();
    private ArrayList<View> mFooterViews = new ArrayList<>();
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.Adapter mWrapAdapter;
    private static final int TYPE_HEADER = -101;
    private static final int TYPE_FOOTER  = -102;
    private static final int TYPE_LIST_ITEM = - 103;
    public XCRecyclerView(Context context) {
        this(context, null);
    }
    public XCRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public XCRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    private void init(Context context){

    }

    @Override
    public void setAdapter(Adapter adapter) {
        mAdapter = adapter;
        mWrapAdapter = new WrapAdapter(mHeaderViews, mFooterViews, adapter);
        super.setAdapter(mWrapAdapter);
        mAdapter.registerAdapterDataObserver(mDataObserver);
    }
    public void addHeaderView(View view){
        mHeaderViews.clear();
        mHeaderViews.add(view);
    }
    public void addFooterView(View view){
        mFooterViews.clear();
        mFooterViews.add(view);
    }
    public int getHeaderViewsCount(){
        return mHeaderViews.size();
    }
    public int getFooterViewsCount(){
        return mFooterViews.size();
    }
    private final RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            mWrapAdapter.notifyDataSetChanged();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
        }

//        @Override
//        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
//            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
//        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
        }
    };
    private class WrapAdapter extends RecyclerView.Adapter<ViewHolder>{

        private Adapter mAdapter;
        private List<View> mHeaderViews;
        private List<View> mFooterViews;
        public WrapAdapter(List<View> headerViews,List<View> footerViews,Adapter adapter){
            this.mAdapter = adapter;
            this.mHeaderViews = headerViews;
            this.mFooterViews = footerViews;
        }

        public int getHeaderCount(){
            return this.mHeaderViews.size();
        }
        public int getFooterCount(){
            return this.mFooterViews.size();
        }
        public boolean isHeader(int position){
            return position >= 0 && position < this.mHeaderViews.size();
        }
        public boolean isFooter(int position){
            return position < getItemCount() && position >= getItemCount() - this.mFooterViews.size();
        }
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(viewType == TYPE_HEADER){
                return new CustomViewHolder(this.mHeaderViews.get(0));
            }else if(viewType == TYPE_FOOTER){
                return new CustomViewHolder(this.mFooterViews.get(0));
            }else{
                return this.mAdapter.onCreateViewHolder(parent,viewType);
            }
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            if(isHeader(position)) return;
            if(isFooter(position)) return;
            int rePosition = position - getHeaderCount();
            int itemCount = this.mAdapter.getItemCount();
            if(this.mAdapter != null){
                if(rePosition < itemCount){
                    Log.v("czm","rePosition/itemCount="+rePosition+"/"+itemCount);
                    this.mAdapter.onBindViewHolder(holder,rePosition);
                    return;
                }
            }
        }
        @Override
        public long getItemId(int position) {
            if (this.mAdapter != null && position >= getHeaderCount()) {
                int rePosition = position - getHeaderCount();
                int itemCount = this.mAdapter.getItemCount();
                if (rePosition < itemCount) {
                    return this.mAdapter.getItemId(rePosition);
                }
            }
            return -1;
        }
        @Override
        public int getItemViewType(int position) {
            if(isHeader(position)){
                return TYPE_HEADER;
            }
            if(isFooter(position)){
                return TYPE_FOOTER;
            }
            int rePosition = position - getHeaderCount();
            int itemCount = this.mAdapter.getItemCount();
            if(rePosition < itemCount){
                return this.mAdapter.getItemViewType(position);
            }
            return TYPE_LIST_ITEM;
        }
        @Override
        public int getItemCount() {
            if(this.mAdapter != null){
                return getHeaderCount() + getFooterCount() + this.mAdapter.getItemCount();
            }else{
                return getHeaderCount() + getFooterCount();
            }
        }

        @Override
        public void registerAdapterDataObserver(AdapterDataObserver observer) {
            if(this.mAdapter != null){
                this.mAdapter.registerAdapterDataObserver(observer);
            }
        }

        @Override
        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
            if(this.mAdapter != null){
                this.mAdapter.unregisterAdapterDataObserver(observer);
            }
        }

        private class CustomViewHolder extends ViewHolder{

            public CustomViewHolder(View itemView) {
                super(itemView);
            }
        }
    }
}

XCRecyclerView

使用方法github里也写的清清楚楚的

private MyAdapter mAdapter;
private XCRecyclerView mRecyclerView;
private List<String> mData;
private View mHeaderView;
private View mFooterView;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mData = new  ArrayList<String>();
    for(int i = 0; i < 10 ;i++){
        mData.add("item_" + i);
    }
    mAdapter = new MyAdapter(mData);
    mRecyclerView = (XCRecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mHeaderView = LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false);
    mFooterView = LayoutInflater.from(this).inflate(R.layout.layout_footer,mRecyclerView,false);
    mRecyclerView.addHeaderView(mHeaderView);
    mRecyclerView.addFooterView(mFooterView);
    mRecyclerView.setAdapter(mAdapter);
}

注意点:

addHeaderView之后 列表的数据坐标即相应发生变化!即addHeadView一次,列表第一个数据的下坐标+1(0-->1)

时间: 2024-10-12 03:48:25

RecyclerView添加头部和底部视图的实现的相关文章

嗯嗯,一句代码就搞定 RecycleView 侧滑菜单、添加头部底部、加载更多

很早就萌生了将这种方案封装为一个开源库的想法,旨在实现调用方式最简单,且又不失可定制性.本库最大的特点的是采用了 Glide 简洁明了的链式调用方式,一句代码即可添加侧滑菜单.头部底部等. 特性: 1.自定义侧滑菜单布局 2.添加头部.底部 3.轻松实现加载更多 4.设置 item 间距 5.多种 item 类型 6.支持 LinearLayout 及 GridLayout 7.一句代码实现所有功能 效果: 左侧滑菜单.右侧滑菜单.自定义菜单布局:      头部.多头部:      底部.多底

可添加头部尾部RecyclerView,很帅哦~

WrapRecyclerView 是一个可以添加头部和尾部的RecyclerView,并且提供了一个 WrapAdapter, 它可以让你轻松为 RecyclerView 添加头部和尾部. 示例中轮转图使用了Android-LoopView,使用它你可以轻松实现轮转大图. 是不是很心动?那么抓紧来star or fork吧! GitHub地址: WrapRecyclerView Android-LoopView https://github.com/xuehuayous/WrapRecycler

Android 5.X新特性之为RecyclerView添加HeaderView和FooterView

上一节我们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信大家也应该熟悉了RecyclerView的基本使用,这一节我们来学习下,为RecyclerView添加HeaderView和FooterView. 针对RecyclerView的头部和底部,官方并没有给我们提供像listView一样可以直接通过addHeaderView()/addFooterView()的方法,所以只能靠我们自己去实现了,那怎么实现呢?大家都知道RecyclerView已经为我们封装

滑动ListView自动隐藏页面头部和底部元素的例子

完整工程代码在这:https://github.com/NashLegend/Auto-Hide-ListView 现在很多软件都有这种滑动列表的时候自动隐藏页面头部和底部元素的功能,比如Google+.在刚刚进入Activity的时候,页面是一个列表,底部有一个view,头部一个view,当列表向上滑动的时候,隐藏头尾元素,以显示更多内容,当列表向下滑动的时候,再将头尾元素拉出来.比如Google+. 刚刚进入时是这个样子: 再把列表身上一拉,头尾隐藏,成了这个样子: 再往下拉,就会再变回第一

HTML5 开发APP(头部和底部选项卡)

我们开发app有一定固定的样式,比如头部和底部选项卡部分就是公共部分就比如我在做的app进来的主页面就像图片显示的那样 我们该怎么实现呢,实现我们应该建一个主页面index.html,然后建五个子页面,通过mui来实现切换功能. 在index的html部分写下这样的代码 <body> <header class="mui-bar mui-bar-nav" style="padding-right: 15px;background: #00be68;"

Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加HeaderView和FooterView,既然来到这里还没学习的,先去学习下吧. 今天我们的主题是学习为RecyclerView添加下拉刷新和上拉加载功能. 首先,我们先来学习下拉刷新,google公司已经为我们提供的一个很好的包装类,那就是SwipeRefreshLayout,这个类可以支持我们向下滑动并进

ionic入门篇(一)[了解]与[头部、底部、副标题]

一].ionic了解:是什么?1.强大的 HTML5 应用程序开发框架(HTML5 Hybrid Mobile App Framework )2.构建接近原生体验的移动应用程序.3.注重外观.体验.交互4.轻量.速度快5.不支持IOS6和Android4.1以下的版本 特点:1.基于Angular语法2.轻量级.简单3.融合下一代移动框架,支持Angular.js特性,MVC,代码易维护4.漂亮.SASS.UI组件多5.原生性强6.ionic提供了强大的命令行工具7.性能优越,运行速度快 ion

iOS 开发之头部滚动展示视图(转)

// //  RootViewController.m //  头部滚动展示视图 //  头部滚动广告视图 #define SCREEN_SIZE [UIScreen mainScreen].bounds.size #define KImageCnt 5 #define KImage_H  250 #import "RootViewController.h" @interface RootViewController ()<UIScrollViewDelegate> @pr

如何在UITableViewController上添加一个固定的视图

最近在使用UITableViewController,想在上面添加一个固定的视图,不随ScrollView滑动而移动.最后找到2种解决办法,一种是计算TableView的偏移,调整视图的位置,不断更新视图,从而达到相对静止.使用UIScrollViewDelegate里的方法-(void) scrollViewDidScroll; -(void)scrollViewDidScroll:(UIScrollView *)scrollView { self.hud.frame = CGRectMake