移动端开发,不联网的App少之又少,所以下拉刷新数据、上拉加载更多数据作为一个基础功能,相关的库层出不穷,这里就记录一下曾经用过的库吧,希望对大家有用。
一、 Android-PullToRefresh
这是最经典的下拉刷新库了。在github上有6952个Star、4746个Fork。在用eclipse开发Android的时代,是必备使用的库之一。
集成方式也很简单。
- eclipse导入lib 源码
- 显示代码:
<!--
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" />
- 控制代码:
// 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>
集成方式很简单:
- 一行导包
compile 'in.srain.cube:ultra-ptr:1.0.11'
- 界面逻辑:
<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>
- 控制逻辑:
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
这个库同时支持下拉刷新和上拉加载更多,集成也很简单:
- 一行导包
dependencies {
compile 'com.android.support:recyclerview-v7:latestVersion'
// 记得添加nineoldandroids
compile 'com.nineoldandroids:library:2.4.0'
compile 'cn.bingoogolapple:bga-refreshlayout:latestVersion@aar'
}
- 界面逻辑:
<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>
- 控制逻辑:
// 让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**
集成步骤同样简单:
- 一行导包
compile 'com.chanven.lib:cptr:1.0.0'
- 界面逻辑
<?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>
- 控制逻辑
这一块可以使用android-Ultra-Pull-To-Refresh的方式,也可以使用** SwipeRefreshLayout**的方式,看需求了。
我现在选择的下拉刷新库就是CommonPullToRefresh,目前使用中还没有发现问题。
Panda
2016-06-13
网友评论
refreshComplete()还是在loading,有个延迟才关闭header,
在分页没有数据的时候使用ptr.loadMoreComplete(false);进行提交的吗?
在第一页的时候,当数据不满一屏的时候怎么去掉footer的显示?
```
是否需要加载更多 默认false mPtrFrame.setLoadMoreEnable(true)
是否自动加载 默认true mPtrFrame.setAutoLoadMoreEnable(true)
```
item的点击事件,只能去加判断了,根据list的size去判断。