美文网首页Android 学习待修改-精通安卓Android技术研究
[49→100]那些年用过的下拉刷新、上拉加载更多的库

[49→100]那些年用过的下拉刷新、上拉加载更多的库

作者: 沉思的Panda | 来源:发表于2016-06-13 22:48 被阅读3942次

移动端开发,不联网的App少之又少,所以下拉刷新数据、上拉加载更多数据作为一个基础功能,相关的库层出不穷,这里就记录一下曾经用过的库吧,希望对大家有用。

一、 Android-PullToRefresh

这是最经典的下拉刷新库了。在github上有6952个Star、4746个Fork。在用eclipse开发Android的时代,是必备使用的库之一。

集成方式也很简单。

  1. eclipse导入lib 源码
  2. 显示代码:
<!--
  The PullToRefreshListView replaces a standard ListView widget.
  The ID CAN NOT be @+id/android:list
-->
<com.handmark.pulltorefresh.library.PullToRefreshListView
    android:id="@+id/pull_to_refresh_listview"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent" />
  1. 控制代码:
// Set a listener to be invoked when the list should be refreshed.
PullToRefreshListView pullToRefreshView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview);
pullToRefreshView.setOnRefreshListener(new OnRefreshListener<ListView>() {
    @Override
    public void onRefresh(PullToRefreshBase<ListView> refreshView) {
        // Do work to refresh the list here.
        new GetDataTask().execute();
    }
});

private class GetDataTask extends AsyncTask<Void, Void, String[]> {
    ...
    @Override
    protected void onPostExecute(String[] result) {
        // Call onRefreshComplete when the list has been refreshed.
        pullToRefreshView.onRefreshComplete();
        super.onPostExecute(result);
    }
}

遗憾的是,这个项目不再维护,最后一次更新日期为2013年2月2号,在Android开发已经进化到gradle一行导包的时代,只能放弃它了。

二、android-Ultra-Pull-To-Refresh

这是国内Android开发大神廖祜秋开发的一个开源库。特点是内置各种下拉刷新交互风格。

  • 下拉刷新(iOS风格)

    <div> </div>
  • 释放刷新(经典风格)

    <div> </div>
  • 刷新时,头部保持(新浪微博)

  • 刷新时,头部不保持(微信朋友圈)

  • 自动刷新,进入界面时自动刷新

    </div>

集成方式很简单:

  1. 一行导包
compile 'in.srain.cube:ultra-ptr:1.0.11'
  1. 界面逻辑:
<in.srain.cube.views.ptr.PtrFrameLayout
    android:id="@+id/store_house_ptr_frame"
    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    cube_ptr:ptr_resistance="1.7"
    cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
    cube_ptr:ptr_duration_to_close="300"
    cube_ptr:ptr_duration_to_close_header="2000"
    cube_ptr:ptr_keep_header_when_refresh="true"
    cube_ptr:ptr_pull_to_fresh="false" >
<LinearLayout
        android:id="@+id/store_house_ptr_image_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/cube_mints_333333"
        android:clickable="true"
        android:padding="10dp">
        <in.srain.cube.image.CubeImageView
            android:id="@+id/store_house_ptr_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
</in.srain.cube.views.ptr.PtrFrameLayout>
  1. 控制逻辑:
ptrFrame.setPtrHandler(new PtrHandler() {
    @Override
    public void onRefreshBegin(PtrFrameLayout frame) {
        frame.postDelayed(new Runnable() {
            @Override
            public void run() {
                ptrFrame.refreshComplete();
            }
        }, 1800);
    }

    @Override
    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
        // 默认实现,根据实际情况做改动
        return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
    }
});

相关原理可以参考作者写的文档——我眼中的下拉刷新

遗憾的是这个库不支持上拉加载更多,作者有提供一个解决方案——android-cube-app,但是这个解决方案是一个demo,而不是内嵌在Ultra-Pull-To-Refresh中,不符合一行导包的原则了。

三、BGARefreshLayout-Android

这个库同时支持下拉刷新和上拉加载更多,集成也很简单:

  1. 一行导包
dependencies {
    compile 'com.android.support:recyclerview-v7:latestVersion'
    // 记得添加nineoldandroids
    compile 'com.nineoldandroids:library:2.4.0'
    compile 'cn.bingoogolapple:bga-refreshlayout:latestVersion@aar'
}
  1. 界面逻辑:
<cn.bingoogolapple.refreshlayout.BGARefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_modulename_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- 内容控件 -->
    <AnyView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</cn.bingoogolapple.refreshlayout.BGARefreshLayout>
  1. 控制逻辑:
// 让activity或者fragment实现BGARefreshLayoutDelegate接口
public class ModuleNameActivity extends AppCompatActivity implements BGARefreshLayout.BGARefreshLayoutDelegate {
    private BGARefreshLayout mRefreshLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_moudlename);
        initRefreshLayout();
    }
    private void initRefreshLayout(BGARefreshLayout refreshLayout) {
        mRefreshLayout = (BGARefreshLayout) findViewById(R.id.rl_modulename_refresh);
        // 为BGARefreshLayout设置代理
        mRefreshLayout.setDelegate(this);
        // 设置下拉刷新和上拉加载更多的风格     参数1:应用程序上下文,参数2:是否具有上拉加载更多功能
        BGARefreshViewHolder refreshViewHolder = new XXXImplRefreshViewHolder(this, true))
        // 设置下拉刷新和上拉加载更多的风格
        mRefreshLayout.setRefreshViewHolder(refreshViewHolder);
        // 为了增加下拉刷新头部和加载更多的通用性,提供了以下可选配置选项  -------------START
        // 设置正在加载更多时不显示加载更多控件
        // mRefreshLayout.setIsShowLoadingMoreView(false);
        // 设置正在加载更多时的文本
        refreshViewHolder.setLoadingMoreText(loadingMoreText);
        // 设置整个加载更多控件的背景颜色资源id
        refreshViewHolder.setLoadMoreBackgroundColorRes(loadMoreBackgroundColorRes);
        // 设置整个加载更多控件的背景drawable资源id
        refreshViewHolder.setLoadMoreBackgroundDrawableRes(loadMoreBackgroundDrawableRes);
        // 设置下拉刷新控件的背景颜色资源id
        refreshViewHolder.setRefreshViewBackgroundColorRes(refreshViewBackgroundColorRes);
        // 设置下拉刷新控件的背景drawable资源id
        refreshViewHolder.setRefreshViewBackgroundDrawableRes(refreshViewBackgroundDrawableRes);
        // 设置自定义头部视图(也可以不用设置)     参数1:自定义头部视图(例如广告位), 参数2:上拉加载更多是否可用
        mRefreshLayout.setCustomHeaderView(mBanner, false);
        // 可选配置  -------------END
    }
    @Override
    public void onBGARefreshLayoutBeginRefreshing(BGARefreshLayout refreshLayout) {
        // 在这里加载最新数据

        if (mIsNetworkEnabled) {
            // 如果网络可用,则加载网络数据
            new AsyncTask<Void, Void, Void>() {

                @Override
                protected Void doInBackground(Void... params) {
                    try {
                        Thread.sleep(MainActivity.LOADING_DURATION);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return null;
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    // 加载完毕后在UI线程结束下拉刷新
                    mRefreshLayout.endRefreshing();
                    mDatas.addAll(0, DataEngine.loadNewData());
                    mAdapter.setDatas(mDatas);
                }
            }.execute();
        } else {
            // 网络不可用,结束下拉刷新
            Toast.makeText(this, "网络不可用", Toast.LENGTH_SHORT).show();
            mRefreshLayout.endRefreshing();
        }
    }

    @Override
    public boolean onBGARefreshLayoutBeginLoadingMore(BGARefreshLayout refreshLayout) {
        // 在这里加载更多数据,或者更具产品需求实现上拉刷新也可以

        if (mIsNetworkEnabled) {
            // 如果网络可用,则异步加载网络数据,并返回true,显示正在加载更多
            new AsyncTask<Void, Void, Void>() {

                @Override
                protected Void doInBackground(Void... params) {
                    try {
                        Thread.sleep(MainActivity.LOADING_DURATION);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return null;
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    // 加载完毕后在UI线程结束加载更多
                    mRefreshLayout.endLoadingMore();
                    mAdapter.addDatas(DataEngine.loadMoreData());
                }
            }.execute();

            return true;
        } else {
            // 网络不可用,返回false,不显示正在加载更多
            Toast.makeText(this, "网络不可用", Toast.LENGTH_SHORT).show();
            return false;
        }
    }
    // 通过代码方式控制进入正在刷新状态。应用场景:某些应用在activity的onStart方法中调用,自动进入正在刷新状态获取最新数据
    public void beginRefreshing() {
        mRefreshLayout.beginRefreshing();
    }
    // 通过代码方式控制进入加载更多状态
    public void beginLoadingMore() {
        mRefreshLayout.beginLoadingMore();
    }
}

但这个库有一个严重的bug

正在刷新或加载更多时,用户上下滑动不会让下拉刷新视图和加载更多视图跟着滑动

这一点在网络慢的时候,非常影响用户体验

四、CommonPullToRefresh

这个库基于android-Ultra-Pull-To-Refresh,封装了加载更多的逻辑,而且还支持Android最新推出的下拉控件** SwipeRefreshLayout**

SwipeRefreshLayout

集成步骤同样简单:

  1. 一行导包
compile 'com.chanven.lib:cptr:1.0.0'
  1. 界面逻辑
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.chanven.lib.cptr.PtrClassicFrameLayout
        android:id="@+id/test_list_view_frame"
        xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f0f0f0"
        cube_ptr:ptr_resistance="1.7"
        cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
        cube_ptr:ptr_duration_to_close="200"
        cube_ptr:ptr_duration_to_close_header="1000"
        cube_ptr:ptr_keep_header_when_refresh="true"
        cube_ptr:ptr_pull_to_fresh="false">

        <ListView
            android:id="@+id/test_list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:choiceMode="singleChoice"
            android:divider="#b0b0b0"
            android:dividerHeight="0.1dp"
            android:fadingEdge="none"
            android:scrollbarStyle="outsideOverlay"/>
    </com.chanven.lib.cptr.PtrClassicFrameLayout>
</LinearLayout>
  1. 控制逻辑
    这一块可以使用android-Ultra-Pull-To-Refresh的方式,也可以使用** SwipeRefreshLayout**的方式,看需求了。

我现在选择的下拉刷新库就是CommonPullToRefresh,目前使用中还没有发现问题。

Panda
2016-06-13

相关文章

网友评论

  • 80ac41b8844a:CommonPullToRefresh 楼主有这个问题吗,.我下拉刷新的时候,是网络请求完成后,设置refreshComplete(),然后更新数据,.当网络请求很快的时候,界面上的数据已经更新完毕了,但是
    refreshComplete()还是在loading,有个延迟才关闭header,
  • _一脸嫌弃:PullToRefresh确实经典,但有一个非常致命的问题,当数据量过大的时候或者布局较复杂的时候,下拉刷新会有"断层"的现象,没办法解决
  • kidz:感谢分享
  • 沉思的Panda:你可以看看这个 http://www.xuebuyuan.com/2191777.html
    b0560b63b4cc:@沉思的Panda 最外层是下拉刷新框架,里面是一个scrollview,scrollview中嵌套了viewpager和listview,viewpager在界面顶部,listview在viewpager下面。
    沉思的Panda:@人心弗远 你是指用Listview嵌套viewpager吗?还是viewpager嵌套Listview啊?
    b0560b63b4cc:@沉思的Panda 不是因为Scrollview嵌套listview的问题,是嵌套了轮播控件后,左右滑动viewpager与下拉刷新冲突,怎么解决,跪求楼主了,想了好久没能解决。
  • b0560b63b4cc:该框架嵌套viewpager后滑动冲突,怎么解决,楼主??,试了几种方法都不行哦。。。。。
  • f3f4672ef98e:CommonPullToRefresh这个库也有问题啊,在Fragment里面用,直接在mPtrFrame.setLoadMoreEnable(true)那里报java.lang.IllegalStateException: unSupported contentView !楼主怎么破啊?
    沉思的Panda:@f3f4672ef98e 哦,你可以到github上给作者反馈,我使用过程中没有碰到这个问题
    f3f4672ef98e:@沉思的Panda 布局文件com.chanven.lib.cptr.PtrClassicFrameLayout中只有一个ScrollView子元素 ScrollView里面只有一个LinearLayout 然后把所有的内容放到这个LinearLayout中 就这样的一个布局 有问题??
    沉思的Panda:@f3f4672ef98e 应该是contentView的个数超过2了吧
  • 菲利柯斯:CommonPullToRefresh这个库,博主在用的时候,有没有点击footer的时候会触发item的点击事件?
    在分页没有数据的时候使用ptr.loadMoreComplete(false);进行提交的吗?
    在第一页的时候,当数据不满一屏的时候怎么去掉footer的显示?
    沉思的Panda:@菲利柯斯 作者在1.1里面增加了两个接口来处理这种情形
    ```
    是否需要加载更多 默认false mPtrFrame.setLoadMoreEnable(true)
    是否自动加载 默认true mPtrFrame.setAutoLoadMoreEnable(true)
    ```
    菲利柯斯:@kyolee footer的显示我把他的源码下载下来,再AS引用的本地的lib,修改一下他的源码,算是解决了,但是不知道完美不,现在没有出问题。
    item的点击事件,只能去加判断了,根据list的size去判断。
    8797e0d3f45b:@菲利柯斯 同样的问题你解决了么!!!~~
  • hackest:最后亮了
  • 大凡:👏👏👏👏👏
  • 浮生如茶2016:写的不错,赞一个!

本文标题:[49→100]那些年用过的下拉刷新、上拉加载更多的库

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