自定义RecyclerView实现下拉刷新,加载更多

RecyclerView出来的时间已经不短了,现在估计大部分的列表类的需求实现首选肯定是RecyclerView,基本上可以跟ListView说再见了。那么问题来了,一般情况下一个列表页面都会有下拉刷新和加载更多功能,RecyclerView本身并没有下拉刷新和加载更多功能,当然现在已经有很多优秀的开源的支持下拉刷新,加载更多功能的三方RecyclerView,可以直接拿过来用。但是。。。有时候光会用是不够的,还需要知道它们是这么实现的,实现的原理是什么。下面就来介绍一下RecyclerView下拉刷新,加载更多功能的实现套路。

要实现的效果

一、下拉刷新view和加载更多的view放在哪?

要达到上面的效果首先要考虑的是这个顶部下拉的刷新的view和底部加载更多的view放在什么地方合适,答案就是自定义一个WrapAdapter适配器,通过包装Adapter来提供header和footer。因为RecyclerView的Adapter是支持显示多种不同类型的view的,只需要重写RecyclerView.Adapter的 getItemViewType(int position)方法,根据不同位置返回不同类型即可。可以利用这个特性把第0个位置和最后一个位置预留出来,固定把第0个item存放下拉刷新的view,把最后一个位置存放加载更多的view。

具体代码如下:

/**
 *  实现显示头部和尾部item的adapter,把头部尾部的事情交给这个adapter来做,其他的交给子adapter
 */
public class MyWrapAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public ArrayList<View> headerViews=new ArrayList<>();
    public ArrayList<View> footViews=new ArrayList<>();
    public RecyclerView.Adapter adapter;

    public MyWrapAdapter(RecyclerView.Adapter adapter, ArrayList<View> headerViews, ArrayList footViews){
        this.adapter=adapter;
        this.headerViews=headerViews;
        this.footViews=footViews;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType== RecyclerView.INVALID_TYPE){
            //头部item
            return new RecyclerView.ViewHolder(headerViews.get(0)){};
        }else if(viewType== (RecyclerView.INVALID_TYPE-1)){
            //尾部item
            return new RecyclerView.ViewHolder(footViews.get(0)){};
        }
        return adapter.onCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(position>=0&&position<headerViews.size()){
            return;
        }

        if(adapter!=null){
            int p=position-headerViews.size();
            if(p<adapter.getItemCount()){
                adapter.onBindViewHolder(holder,p);
            }
        }
    }

    @Override
    public int getItemViewType(int position) {
        if(position>=0&&position<headerViews.size()){
            //如果是头部则返回一个不可用的标识,表示这是头部item
            return RecyclerView.INVALID_TYPE;
        }

        if(adapter!=null){
            int p=position-headerViews.size();
            if(p<adapter.getItemCount()){
                return adapter.getItemViewType(p);
            }
        }

        return RecyclerView.INVALID_TYPE-1;//默认返回表示是尾部的item
    }

    @Override
    public int getItemCount() {
        return getCount();
    }

    public int getCount(){
        int count=headerViews.size()+footViews.size();
        if(adapter!=null){
            count+=adapter.getItemCount();
        }
        return count;
    }

}

二、下拉刷新的实现

整体实现下拉刷新的思路是,当把下拉刷新view添加到adapter中的第0个item的时候,高度是0,也就看不见下拉刷新的view。当我们下拉刷新的时候根据滑动的值来设置下拉刷新view的高度,这样下拉刷新的view就慢慢的显示出来了。但是现在的效果是,先看到的是顶部,下拉刷新view是从顶部开始一点一点显示的。这样的效果当然可以,但是我们需要的效果是下拉刷新的view从底部开始一点点显示出来,做如下调整,我们一开始让下拉刷新的view的高度就是自身高,让它距离顶部的距离是负的自身高度,这样正好就看不见了。并且把下拉刷新view的Gravity设置为Gravity.BOTTOM,这样当我们滑动的时候下拉刷新的view就会从底部开始一点一点显示出来。

现在思路是有了,但是实现的时候,需要解决下面几个问题:

1、下拉刷新只有在滑动到顶部的时候,才会触发下拉刷新,那么RecyclerView如何判断滑动到了顶部?

研究了几个开源的下拉刷新RecyclerView,发现每个实现的方法都不太一样,踩了几个坑后。决定用

ViewCompat.canScrollVertically()这个方法来实现,这个方法能够检测出RecyclerView是否滑动到了顶部或底部。

2、如何获得滑动的值

这个老套路了,通过重写RecyclerView的onTouchEvent来计算获得。还有一共方式可以获得滑动的值,重写LayoutManager的scrollVerticallyBy方法这个方法的参数值是LayoutManager帮我们计算好的滑动距离,但是用这种方式还得自己包一个LayoutManager,所以不考虑,还是老套路吧。。。

三、加载更多的实现

加载更多就比较好实现了,核心是如何判断recyclerview滚动到了底部。

一种思路给RecyclerView添加addOnScrollListener监听,重写onScrollStateChanged方法,在这里面判断最后一个可见的view是否是最后一个item即可。

判断的代码如下:

this.addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (isRefresh) {
                    return;
                }
                if (mState != STATE_NORMAL) {
                    return;
                }
                //判断是否最后一item个显示出来
                LayoutManager layoutManager = getLayoutManager();

                //可见的item个数
                int visibleChildCount = layoutManager.getChildCount();
                if (visibleChildCount > 0 && newState == RecyclerView.SCROLL_STATE_IDLE && !isLoadMore) {
                    View lastVisibleView = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
                    int lastVisiblePosition = recyclerView.getChildLayoutPosition(lastVisibleView);
                    if (lastVisiblePosition >= layoutManager.getItemCount() - 1) {
                        footerView.setVisibility(VISIBLE);
                        isLoadMore = true;
                        if (myRecyclerViewListener != null) {
                            myRecyclerViewListener.onLoadMore();
                        }
                    } else {
                        footerView.setVisibility(GONE);
                    }
                }

            }
        });

源码

时间: 2024-12-13 06:37:39

自定义RecyclerView实现下拉刷新,加载更多的相关文章

Android UI--自定义ListView(实现下拉刷新+加载更多)

http://blog.csdn.net/wwj_748/article/details/12512885 Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的.因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想把这个UI整合到项目当中去,这里只是一个demo,可以根据项目的需要进行修改. 就不要太在乎界面了哈:

Android Demo 下拉刷新+加载更多+滑动删除

小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第一时间掌握最新消息,加载更多是什么nie,简单来说就是在网页上逛淘宝的时候,我们可以点击下一页来满足我们更多的需求,但是在手机端就不一样了,没有上下页,怎么办nie,方法总比困难多,细心的小伙伴可能会发现,在手机端中,有加载更多来满足我们的要求,其实加载更多也是分页的一种体现.小伙伴在使用手机版QQ

Android之RecyclerView轻松实现下拉刷新和加载更多

今天研究了下RecyclerView的滑动事件,特别是下拉刷新和加载更多事件,在现在几乎所有的APP显示数据列表时都用到了.自定义RecyclerView下拉刷新和加载更多听上去很复杂,实际上并不难,只要是对滑动事件的监听和处理. 一.自定义RecyclerView实现下拉刷新和加载更多 1.如何判断RecyclerView是在上滑还是下滑 在RecyclerView的OnScrollListener滑动事件监听中有个好用的方法,就是onScrolled(RecyclerView recycle

Android智能下拉刷新加载框架—看这些就够了

一些值得学习的几个下拉刷新上拉加载开源库 Android智能下拉刷新框架-SmartRefreshLayout 支持所有的 View(AbsListView.RecyclerView.WebView....View) 和多层嵌套的视图结构 支持自定义并且已经集成了很多炫酷的 Header 和 Footer (图). 支持和ListView的同步滚动 和 RecyclerView.AppBarLayout.CoordinatorLayout 的嵌套滚动 NestedScrolling. 支持在An

listview 下拉刷新加载数据

点击头条,头条会变成以下: 然后,过一段时间,刷新完成以后,listview又setSelection(1),增加一条数据,同时,把顶部给遮挡住: 这是点击刷新,然后是下拉刷新: 最后结果和点击刷新相同.那现在开始看下代码: 首先看下所用到的控件和变量: // 状态 private static final int TAP_TO_REFRESH = 1;//点击刷新 private static final int PULL_TO_REFRESH = 2;  //拉动刷新 private sta

uni-app下拉刷新加载刷新数据

onPullDownRefresh 监听该页面用户下拉刷新事件 需要在 pages.json 里 开启 enablePullDownRefresh "globalStyle": { } 当处理完数据刷新后,uni.stopPullDownRefresh 可以停止当前页面的下拉刷新 uni.startPullDownRefresh(OBJECT) success Function 否 接口调用成功的回调 fail Function 否 接口调用失败的回调函数 complete Funct

自己封装的工具类,使用原生SwipeRefreshLayout+RecycleView实现下拉刷新和加载更多

实现SwipeRefreshLayout+RecycleView实现刷新 在你的xml文件里写上如下代码: <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/SwipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <andr

iOS 下拉刷新和加载更多 (OC\Swift)

Swift语言出来之后, 可能还没有第三方的下拉刷新和上提加载, 所以自己用UIRefreshControl控件和UITableView实例的tableFooterView(底部视图)属性结合起来写了一个下拉刷新和点击加载更多的基本实现, 分为OC的代码实现和Swift的代码实现, 希望大家可以指出不足: Swift代码: 1 import UIKit 2 3 class ViewController: UITableViewController { 4 5 // 用于显示的数据源 6 var

下拉滚动加载更多数据

简单地实现一个下拉滚动时加载更多数据的效果.这种效果经常在手机端.瀑布流时看到 1 KISSY.add('load',function(S,Core,IO,XTemplate){ 2 var $ = S.all, D = S.DOM, E = S.Event; 3 var API = { 4 'query':'query.do' 5 }; 6 var tpl = '{{#each result}}'+ 7 '<tr>'+ 8 '<td><input type="ch