美文网首页自定义控件
Android LRecyclerView实现下拉刷新,滑动到底

Android LRecyclerView实现下拉刷新,滑动到底

作者: jdsjlzx | 来源:发表于2016-07-23 21:45 被阅读8290次

    很想给大家分享这个开源项目,但是由于工作的关系,没有抽出空,但还是趁着工作间隙写下了这篇博客。

    简介

    LRecyclerView是支持addHeaderView、 addFooterView、下拉刷新、分页加载数据的RecyclerView。

    它对 RecyclerView 控件进行了拓展,给RecyclerView增加HeaderView、FooterView,并且不需要对你的Adapter做任何修改。

    主要功能

    1. 下拉刷新、滑动到底部自动加载下页数据;
    2. 可以方便添加Header和Footer;
    3. 头部下拉样式可以自定义;
    4. 具备item点击和长按事件。
    5. 网络错误加载失败点击Footer重新请求数据;
    6. 可以动态为FooterView赋予不同状态(加载中、加载失败、滑到最底等)。

    项目地址:https://github.com/jdsjlzx/LRecyclerView

    感谢

    如果我比别人看得远些,那是因为我站在巨人们的肩上。 (牛顿)

    本开源控件是基于 HeaderAndFooterRecyclerView 开源项目而来,在原基础上进行了扩充。在此感谢cundong作者(github地址:https://github.com/cundong)。

    效果图

    这里写图片描述

    下拉刷新

    为了达到和Listview的下拉刷新效果,本项目没有借助SwipeRefreshLayout控件,而是在自定义RecyclerView头部实现的刷新效果。

    这里的下拉刷新效果借鉴了开源库:AVLoadingIndicatorView

    设置加载样式:

    mRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);
    mRecyclerView.setArrowImageView(R.drawable.iconfont_downgrey);
    

    AVLoadingIndicatorView库有多少效果,LRecyclerView就支持多少下拉刷新效果,当然你也可以自定义下拉效果。

    效果图:

    这里写图片描述

    下拉刷新逻辑处理:

    从上面的LScrollListener介绍中就可以看出,实现下拉刷新只要在onRefresh()接口中处理即可。

    加载网络异常处理

    加载数据时如果网络异常或者断网,LRecyclerView为你提供了重新加载的机制。

    效果图:

    这里写图片描述这里写图片描述

    网络异常出错代码处理如下:

    RecyclerViewStateUtils.setFooterViewState(getActivity(), mRecyclerView, getPageSize(), LoadingFooter.State.NetWorkError, mFooterClick);
    
    private View.OnClickListener mFooterClick = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                RecyclerViewStateUtils.setFooterViewState(getActivity(), mRecyclerView, getPageSize(), LoadingFooter.State.Loading, null);
                requestData();
            }
        };
    

    上面的mFooterClick就是我们点击底部的Footer时的逻辑处理事件,很显然我们还是在这里做重新请求数据操作。

    点击事件和长按事件处理

    在Hongyang前辈的博客中有下描述:

    Click and LongClick

    不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。
    不过我们也可以自己去添加,只是会多了些代码而已。
    实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 当然你也可以通过adapter中自己去提供回调,这里我们选择后者,前者的方式,大家有兴趣自己去实现。

    出自:http://blog.csdn.net/lmj623565791/article/details/45059587

    Hongyang大神选择了后者,LRecyclerView早期选择了前者,经过实践总结,在adapter中实现点击事件会好点。

    先看下怎么使用:

    mHeaderAndFooterRecyclerViewAdapter.setOnItemClickLitener(new OnItemClickLitener() {
                @Override
                public void onItemClick(View view, int position) {
                    
                }
    
                @Override
                public void onItemLongClick(View view, int position) {
                    
                }
            });
    

    原理就是实现viewHolder.itemView的点击和长按事件。由于代码过多就不贴出来了。

    viewHolder.itemView是RecyclerView.Adapter中本身就具有的,不用额外定义。

    源码如下:

    public static abstract class ViewHolder {
            public final View itemView;
            int mPosition = NO_POSITION;
            int mOldPosition = NO_POSITION;
            long mItemId = NO_ID;
            int mItemViewType = INVALID_TYPE;
            int mPreLayoutPosition = NO_POSITION;
    

    设置空白View(setEmptyView)

    mRecyclerView.setEmptyView(view);
    

    注意布局文件:

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    
        <com.cundong.recyclerview.LRecyclerView
            android:id="@+id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
    
        <include
            android:id="@+id/empty_view"
            layout="@layout/layout_empty"
            android:visibility="gone"/>
    </RelativeLayout>
    
    

    分享

    介绍完了LRecyclerView,似乎还少些什么,对了,那就是adapter了。

    为了方便大家使用,分享个封装过的adapter。

    public class ListBaseAdapter<T extends Entity> extends RecyclerView.Adapter {
        protected Context mContext;
        protected int mScreenWidth;
    
        public void setScreenWidth(int width) {
            mScreenWidth = width;
        }
    
        protected ArrayList<T> mDataList = new ArrayList<>();
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return null;
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    
        }
    
        @Override
        public int getItemCount() {
            return mDataList.size();
        }
    
        public List<T> getDataList() {
            return mDataList;
        }
    
        public void setDataList(Collection<T> list) {
            this.mDataList.clear();
            this.mDataList.addAll(list);
            notifyDataSetChanged();
        }
    
        public void addAll(Collection<T> list) {
            int lastIndex = this.mDataList.size();
            if (this.mDataList.addAll(list)) {
                notifyItemRangeInserted(lastIndex, list.size());
            }
        }
    
        public void clear() {
            mDataList.clear();
            notifyDataSetChanged();
        }
    }
    
    

    ListBaseAdapter使用了泛型,简单方便,消除了强制类型转换。

    使用如下:

    private class DataAdapter extends ListBaseAdapter<ItemModel>{
    
            private LayoutInflater mLayoutInflater;
    
            public DataAdapter(Context context) {
                mLayoutInflater = LayoutInflater.from(context);
                mContext = context;
            }
    
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                return new ViewHolder(mLayoutInflater.inflate(R.layout.sample_item_text, parent, false));
            }
    
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                ItemModel item = mDataList.get(position);
    
                ViewHolder viewHolder = (ViewHolder) holder;
                viewHolder.textView.setText(item.title);
            }
    
    
            private class ViewHolder extends RecyclerView.ViewHolder {
    
                private TextView textView;
    
                public ViewHolder(View itemView) {
                    super(itemView);
                    textView = (TextView) itemView.findViewById(R.id.info_text);
                }
            }
        }
    

    ListBaseAdapter虽然功能不强大,但是使用很方便。

    结语

    LRecyclerView使用方便简单,无论你添加多少Header和Footer,你都不用担心position的问题,除了方便还是方便。

    最后再介绍下项目地址:https://github.com/jdsjlzx/LRecyclerView

    如果觉得上面的例子UI简单,这里再分享个公司项目:https://github.com/jdsjlzx/Community

    效果图:

    这里写图片描述这里写图片描述

    如果大家使用过程中有任何问题,请留言,我会及时修正。

    后记:如果后续再增加功能,请详细看github上面的项目介绍,将不在博客里面更新。

    相关文章

      网友评论

      • Lna_35da:之前用在一个项目中效果很好,很灵活。但是这次用的时候不知道是不是我个人原因,在下拉刷新的时候刷新的view不能够正常显示。求楼主帮忙看看
        jdsjlzx:@Lna_35da 加我qq:573842281
      • 一只懂音乐的码虫:作者你好,我用LrecyclerView添加了HeaderView,但是里面的控件无法响应点击事件,就解答:sob:很着急
        一只懂音乐的码虫:谢谢作者,已经解决了,是我布局的问题,不过连续添加多个头部会有问题,具体我没有解决,我觉得您可以完善一下加多个头部的功能
        jdsjlzx:@zlice 你在demo里面试试!如果还有问题,进群群号:183899857 找我!
      • 83e7e587351d:大神:为什么SwipeRefreshLayout + LuRecyclerView 在fragment 里面不能加载呢?activity里面就没有任何问题,求大神解惑。。。fragment 就继承的fragment
      • 小昆:谢谢大神。
        反馈个问题,如果item不满一页,item的底部会有一个空白的footer,没有提示数据已经加载完成。
        小昆:比如只有一条数据的时候 就没有显示
      • 931eb9bcb742:博主你好,我在新项目中用了你的LRecyclerview,是很方便,非常感谢。我遇到一个小问题,请教一下,底部添加的布局,如果数据内容多而body数据少的时候,body部分会被顶上去消失了,这个问题怎么解决呢?
      • Mr_Jing:如何改变下拉刷新的距离偏移量,因为我发现需要滑动挺长的距离才能下拉刷新
      • ad43d9530e75:底部有空白 ,更新最新版本 错误:Error:Execution failed for task ':app:processDebugManifest'.
        > Manifest merger failed : Attribute meta-data#android.support.VERSION@value value=(25.3.1) from [com.android.support:appcompat-v7:25.3.1] AndroidManifest.xml:27:9-31
        is also present at [com.android.support:support-v4:26.0.0-alpha1] AndroidManifest.xml:27:9-38 value=(26.0.0-alpha1).
        Suggestion: add 'tools:replace="android:value"' to <meta-data> element at AndroidManifest.xml:25:5-27:34 to override.
      • peng_fei:底部有空白呀,。。。最新的了已经
      • 你好_ddb0:个人项目也用到它,十分强大。只是后面对adapter封装那里,特别是涉及到泛型,一直都理解不了。
      • 太阳当空照_91ba:舟神,你这个recyclerview设置了emptyview后,触发不到OnRefreshListener呢,怎么解决
        在路上_4bb2:@太阳当空照_91ba 我是在请求完数据后设置emptyview,感觉没有效果
        太阳当空照_91ba:@jdsjlzx 好的 我试试 谢谢舟神
        jdsjlzx:设置了emptyview后,recyclerview被隐藏了,你可以在emptyview上面设置点击事件,触发刷新!
      • 8749a1829c46:您好,请问一下怎么使用DiffUtil在刷新adapter数据时
      • f66a190500cc:舟神,如果添加了新的数据,然后用刷新就会报错。请问是什么原因
        com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
        jdsjlzx:@Jack921 不要SwipeRefreshLayout与LRecyclerView一起使用,会有冲突,为了更好的满足广大用户,新增了LuRecyclerView类,可以与SwipeRefreshLayout搭配使用,详细请参考SwipeRefreshLayoutActivity类的实现。
        Jack921:请问要结合SwipeRefreshLayout控价怎么使用
        jdsjlzx:详见demo的例子使用,你的错误应该josb解析出的问题
      • huigegood:横向的时候前面会空白一片
      • V1tas:如果item不满一页,item的底部会有一个空白的footer,有办法隐藏么
        V1tas:@jdsjlzx 看看
        jdsjlzx:已经解决问题了,常回来看看
      • Luke_单车:舟神,这个LRecyclerView确实蛮强大
        问个问题哈:我fragment布局是CoordinatorLayout,AppBarLayout,Toolbar,viewpager, 然后页面显示数据是RecyclerView,但是RecyclerView不能上下滑动,有点不解。。
        jdsjlzx:@Lukey丶 参照demo中的CollapsingToolbarLayoutActivity 类!
      • xyyou123:舟神 community 登录不了
        jdsjlzx: @xyyou123 屏蔽登陆逻辑就可以了。你修改下
      • 99a3e443b0b3:很不错的第三方,在项目中已应用
        jdsjlzx:@CocoLoveLt 详见github,readme有介绍,下载源码里面有demo!
        CocoLoveLt:@cnoldtree 您是怎么嵌入到项目中的,求分享步骤!

      本文标题:Android LRecyclerView实现下拉刷新,滑动到底

      本文链接:https://www.haomeiwen.com/subject/dsuwjttx.html