RecyclerView 轻松实现下拉刷新,上拉加载更多,添加HeaderView

一,下拉加载更多

用SwipeRefreshLayout 包裹RecyclerView

如下布局文件代码所示:

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recylerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.v4.widget.SwipeRefreshLayout>

Java代码如下所示:

    mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
    mRefreshLayout.setColorSchemeColors(Color.BLUE, Color.GREEN, Color.RED, Color.YELLOW);
      mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
           @Override
           public void onRefresh() {
               Log.d(TAG, "refreshing-------------->");
               Handler handler = new Handler();
               handler.postDelayed(new Runnable() {
                   @Override
                   public void run() {
                       mList.add(0, "新的");
                       mMyAdapter.notifyDataSetChanged();
                       mRefreshLayout.setRefreshing(false);
                   }
               }, 2000);
            }
        });

为RecyclerView添加下拉刷新监听mRefreshLayout.setOnRefreshListener(mOnRefreshListener);
利用以上代码便可简单实现下拉刷新。

二、上拉加载更多,添加HeaderView

上拉加载更多、添加HeaderView稍微复杂些,按照下面几个步骤便可实现。
HeaderView:显示头部View
NormalView:显示正常条目的View
FooterView:显示加载更多的View

1、重写RecyclerView.Adapter的getItemCount()方法

因为添加了HeaderView和FooterView,在重写getItemCount()方法的时候要注意加上HeaderView和FooterView2个View的个数,在编程的时候可以根据是否添加了HeaderView和FooterView来动态的设置个数,如:

    @Override
    public int getItemCount() {
        return list == null ? totalAddationalItems() : list.size() + totalAddationalItems();
    }

    private int totalAddationalItems() {
        int offset = 0;
        if (mIsLoadmore) offset++;
        if (mIsHeader) offset++;
        Log.d(TAG,"offset:"+offset);
        return offset;
    }

2、重写RecyclerView.Adapter的getItemViewType()

利用getItemViewType返回的类型判断是加载HeaderView、NormalView还是FooterView.如:

    private static final int HEADER_TYPE = 0;
    private static final int NORMAL_TYPE = 1;
    private static final int FOOTER_TYPE = 2;
    @Override
    public int getItemViewType(int position) {
        int last_item = getItemCount() - 1;//最后一个
        Log.d(TAG,"getItemViewType position:"+(position-1)+" last_item:"+last_item);
        if (position == 0 && mIsHeader) {
            return HEADER_TYPE;
        } else if (position == last_item && mIsLoadmore) {
            return FOOTER_TYPE;
        }else {
            return NORMAL_TYPE;
        }
    }

3、重写RecyclerView.Adapter的onCreateViewHolder() 方法

重写该方法,实现根据不同的类型加载不同的View

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == NORMAL_TYPE) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recycler_item, parent, false);
            return new MyViewHolder(view);
        } else if (viewType == FOOTER_TYPE) {
            mFooterView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.footer_layout, parent, false);
            mFooterHolder = new MyFooterHolder(mFooterView);
            return mFooterHolder;
        } else if (viewType == HEADER_TYPE) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.header_view_layout, parent, false);
            return new MyHeaderView(view);
        } else {
            return null;
        }
    }

4、重新RecyclerView.Adapter的onBindViewHolder()方法

重写该方法的时候要注意position和数据源List的索引的区别,需要将position-1才和List的索引对称。

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (NORMAL_TYPE == getItemViewType(position)) {
            if (list != null && list.size() > position - 1 && position - 1 >= 0) {
                Log.d(TAG, "onBindViewHolder position:" + (position - 1));
                MyViewHolder myViewHolder = (MyViewHolder) holder;
                myViewHolder.tv.setText(list.get(position - 1));
            }
        }
    }

5、处理FooterView 显示加载更多的View

这一步是处理FooterView的显示和隐藏,当还有数据要加载的时候显示FooterView并请求数据,
FooterViewHolder:

    public static class MyFooterHolder extends RecyclerView.ViewHolder {
        private View mLoadingView;
        private View mEndView;

        public MyFooterHolder(View itemView) {
            super(itemView);
            mLoadingView = itemView.findViewById(R.id.loading_vs);
            mEndView = itemView.findViewById(R.id.end_viewstub);
        }

        public void setData(ITEM_STATUS status) {
            switch (status) {
                case NORMAL:
                    setAllGone();
                    break;
                case LOADING:
                    setAllGone();
                    mLoadingView.setVisibility(View.VISIBLE);
                    Log.d("ad", "ddddd");
                    break;
                case END:
                    setAllGone();
                    break;
            }
        }
        private void setAllGone() {
            mLoadingView.setVisibility(View.GONE);
            mEndView.setVisibility(View.GONE);
        }
    }

6、实现RecyclerView.OnScrollListener

这一步非常重要,用于判断RecyclerView是否滑动到底部。主要是找到mLastVisibleItemPosition的值,根据不同的layoutManager做不同的处理,为RecyclerView添加滚动监听mRecyclerView.addOnScrollListener(mOnScrollListener);

    public void setFooterStatus(MyAdapter.ITEM_STATUS footerStatus) {
        this.mFooterStatus = footerStatus;
        changeFooterViewState();
    }

    private void changeFooterViewState(){
        if (mMyAdapter != null && mMyAdapter.getFooterHolder() != null){
            Log.d(TAG, "changeFooterViewState-------------->");
            mMyAdapter.getFooterHolder().setData(this.mFooterStatus);
        }
    }

    SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            Log.d(TAG, "refreshing-------------->");
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mList.add(0, "新的");
                    mMyAdapter.notifyDataSetChanged();
                    mRefreshLayout.setRefreshing(false);
                }
            }, 2000);
        }
    };

    private abstract class CustomOnScrollListener extends RecyclerView.OnScrollListener {
        private LayoutManagerType mLayoutManagerType;
        private int mLastVisibleItemPosition;
        private int[] mLastVisibleItemPositionStaggered;
        private int mCurrentScrollState;

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (mLayoutManagerType == null) {
                if (layoutManager instanceof GridLayoutManager) {
                    mLayoutManagerType = LayoutManagerType.GRID;
                } else if (layoutManager instanceof LinearLayoutManager) {
                    mLayoutManagerType = LayoutManagerType.LINEAR;
                } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                    mLayoutManagerType = LayoutManagerType.STAGGERED_GRID;
                } else {
                    throw new RuntimeException("not support");
                }
            }
            switch (mLayoutManagerType) {
                case LINEAR:
                    mLastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                    break;
                case GRID:
                    mLastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                    break;
                case STAGGERED_GRID:
                    StaggeredGridLayoutManager sg = (StaggeredGridLayoutManager) layoutManager;
                    if (mLastVisibleItemPositionStaggered == null) {
                        mLastVisibleItemPositionStaggered = new int[sg.getSpanCount()];
                    }
                    sg.findLastVisibleItemPositions(mLastVisibleItemPositionStaggered);
                    mLastVisibleItemPosition = findMax(mLastVisibleItemPositionStaggered);
                    break;
            }
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            mCurrentScrollState = newState;
            int visiableItemCount = recyclerView.getLayoutManager().getChildCount();
            int totalItemCount = recyclerView.getLayoutManager().getItemCount();
            if (visiableItemCount > 0 && mCurrentScrollState == RecyclerView.SCROLL_STATE_IDLE
                    && mLastVisibleItemPosition >= totalItemCount - 1) {
                onLoadMore(recyclerView);
            }
        }

        public abstract void onLoadMore(RecyclerView recyclerView);
    }

    private enum LayoutManagerType {
        LINEAR,
        GRID,
        STAGGERED_GRID,
    }


    private RecyclerView.OnScrollListener mOnScrollListener = new CustomOnScrollListener() {
        @Override
        public void onLoadMore(RecyclerView recyclerView) {
            if (mFooterStatus == MyAdapter.ITEM_STATUS.LOADING){
                return;
            }
            Log.d(TAG, "onLoadMore----->");
            if (mList.size() < 30){
                requestData();
            }else {
                mMyAdapter.enableLoadmore(false);
                //mMyAdapter.enableHeader(false);
                setFooterStatus(MyAdapter.ITEM_STATUS.END);
                mMyAdapter.notifyDataSetChanged();
            }
        }
    };


    private void requestData() {
        setFooterStatus(MyAdapter.ITEM_STATUS.LOADING);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                int start = mMyAdapter.getItemCount()-1;
                mList.add("str"+(mList.size()+1));
                mList.add("str"+(mList.size()+1));
                mList.add("str"+(mList.size()+1));
                if (mList.size() >= 30){
                    mMyAdapter.enableLoadmore(false);
                    //mMyAdapter.enableHeader(false);
                    setFooterStatus(MyAdapter.ITEM_STATUS.END);
                }else {
                    setFooterStatus(MyAdapter.ITEM_STATUS.NORMAL);
                }
                mMyAdapter.notifyDataSetChanged();
            }
        }, 1500);
    }

    private int findMax(int[] lastPositions) {
        int max = Integer.MIN_VALUE;
        for (int value : lastPositions) {
            Log.d(TAG, "value:" + value + " max:" + max);
            if (value > max)
                max = value;
        }
        return max;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值