目前下拉刷新已经满大街都是,在自己的应用如果不使用这个模式的话,出门都不好意思和人家打招呼,该文章就是简单探讨下针对于 github 上的这个开源项目的使用心得。
为什么是它?因为在 stackoverflow 上大家都说它不错,所以就试试看吧!该项目的位置 Android-PullToRefresh 遗憾的是目前已经停止维护,但是已经足够强大所以不维护就不维护吧!
注意:对应的还有一个项目,也是这个作者刚刚开的 ActionBar-PullToRefresh 这个是在 actionbar 上增加下拉的效果,Android-PullToRefresh 这个工程在我们下拉的时候会有一个 view 显示出来,而这个工程直接就是利用 actionbar 来显示,注意这两者的区别
首先,看看目前几个主流 app 的下拉刷新的效果。
sina 微博
网易新闻
腾讯微博
接下来,是我们自己实现后的效果
从图片来看非常的相似,所以接下来我们就看看这个开源的 lib 如何使用。
源码下载下来之后将 library 这个目录中的代码放到一个位置,然后在主工程中去引用它,通常都是在主工程的 project.properties 中去指定引用的位置
- android.library.reference.4=library/Android-PullToRefresh
因为这个是我工程中加入的第四个引用的库,所以是 reference.4,如果这是你的第一个的话,那么应该是 reference.1,这个关于库的引用在 android sdk 的 samples 目录下可以找到了两个工程 " TicTacToeLib " 和 " TicTacToeMain " 来自己参考下。
好了,先 build 下Android-PullToRefresh 生成 jar 包,然后在 build 主工程,应该没什么问题,继续。
接下来就关于这个部分的使用,使用主要考虑两个方法:1. 这个 lib 的基本功能的使用,2. 这个 lib 的自定义扩展
基本功能的使用
1. 在 layout 文件中对应的 listview 不能使用 android 原生的 listview,而是要使用 PullToRefreshListView 代码如下
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
- <com.handmark.pulltorefresh.library.PullToRefreshListView
- xmlns:ptr="http://schemas.android.com/apk/res-auto"
- android:id="@+id/my_list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:cacheColorHint="#00000000"
- android:fadingEdge="none"
- android:fastScrollEnabled="false"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:smoothScrollbar="true"
- ptr:ptrAnimationStyle="flip"
- ptr:ptrHeaderTextAppearance="@android:attr/textAppearanceMedium"/>
- <!-- Here is the view to show if the list is emtpy -->
- <ScrollView android:id="@+id/empty"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:fillViewport="true">
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- android:id="@+id/emptyText"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:text="@string/noText"
- android:textSize="20sp"
- android:textColor="?android:attr/textColorSecondary"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:paddingTop="10dip"
- android:lineSpacingMultiplier="0.92"
- android:gravity="center" />
- </LinearLayout>
- </ScrollView>
- </LinearLayout>
关于 ptr:XXX 属性的使用,会在自定义扩展的那个部分解释下,这里暂时跳过。
2. 在代码中使用这个 listview,代码如下
- private PullToRefreshListView mList;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // ...
- mList = (PullToRefreshListView)findViewById(R.id.my_list);
- mList.setEmptyView(findViewById(R.id.empty));
- mList.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (DEBUG) Log.d(TAG, "onItemClick() : pos=" + position + ", id=" + id);
- parent.getAdapter().getItem(position); // @warning: Should not use mAdapter
- // do something
- }
- });
- mList.setOnPullEventListener(new OnPullEventListener<ListView>() {
- @Override
- public void onPullEvent(PullToRefreshBase<ListView> refreshView, State state,
- Mode direction) {
- if (DEBUG) Log.d(TAG, "onPullEvent() : " + state.name());
- if (state.equals(State.PULL_TO_REFRESH)) {
- refreshView.getLoadingLayoutProxy().setPullLabel(getString(R.string.pull_to_refresh));
- refreshView.getLoadingLayoutProxy().setReleaseLabel(getString(R.string.release_to_refresh));
- refreshView.getLoadingLayoutProxy().setRefreshingLabel(getString(R.string.loading));
- String label = DateUtils.formatDateTime(getApplicationContext(),
- System.currentTimeMillis(),
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
- // Update the LastUpdatedLabel
- refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(
- getString(R.string.updated) + " : " + label);
- }
- }
- });
- mList.setOnRefreshListener(new OnRefreshListener<ListView>() {
- @Override
- public void onRefresh(PullToRefreshBase<ListView> refreshView) {
- if (DEBUG) Log.d(TAG, "onRefresh()");
- // Do work to refresh the list here.
- refresh();
- }
- });
- // ...
- }
1. 如果想对 list item 点击之后做一些事情,此处有个问题要注意下,那就是我们的下来显示的 view 是 header view,所以此处在 onItemClick() 函数中传入的 position 不是从 0 开始而是从 1 开始,如果我们使用通常情况下的 mAdapter 去 getItem() 则实际中始终获取的都是我们点击 item 的下一个 item 的位置,所以此处我们要通过传进来的 parent 的 adapter 来获取 item,详细可以参考 当ListView有Header时,onItemClick里的position不正确
2. 因为下拉的时候显示的文字,每个人有每个的需求,所以会不一样,所以就需要使用 setOnPullEventListener() 来更新文字,这个开源库自己提供的 sample 中更新文字是放到 setOnRefreshListener() 中,但是那个只是在刷新的时候才更新问题,通过对比那些常用 app 的下拉效果你会发现那个时候在更新已经慢了,所以要放到这里
3. 此处代码没有列出来,就是 refresh 完了之后要把 pull view hide 起来,调用 onRefreshComplete() 即可,详情可以参考它自己提供的 sample。
4. 还要注意的是,还有很大的需求是点击刷新,那么点击之后这个 pull view 也要 show 出来,但是不应该 show "下拉可以刷新" 和 "松开可以刷新" 这两个画面,而是直接显示正在刷新的那个画面,这要怎么做到的呢?通过setRefreshing()这个函数即可做到,对应有另外一个函数叫做demo() 它包括了 “下拉->松开->刷新” 的整个过程,这是我们在这种条件下不需要的。
5. 在它自己的 sample 中还可以增加声音的效果,这个比较简单,自己看下即可。
Android-PullToRefresh 自定义扩展
此处的扩展指的是不修改这个开源库任何一行本身的代码来实现自定义一些属性,那些属性可以自定义这个可以在这个库的 values/attrs.xml 中看到,我们使用的时候就像上面 layout 中的写法一样,首先包含下命名空间,然后就可以指定对应的属性
- <com.handmark.pulltorefresh.library.PullToRefreshListView
- xmlns:ptr="http://schemas.android.com/apk/res-auto"
- android:id="@+id/my_list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:cacheColorHint="#00000000"
- android:fadingEdge="none"
- android:fastScrollEnabled="false"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:smoothScrollbar="true"
- ptr:ptrAnimationStyle="flip"
- ptr:ptrHeaderTextAppearance="@android:attr/textAppearanceMedium"/>
一些属性的简单说明
ptrAnimationStyle : flip 这个效果是有向下和向上的两个箭头的,rotate 没有箭头不管怎么拉都是一个 progress bar
ptrMode :both 指的是 listview 的上面和下面都有这种拉动刷新的效果,下面的刷新通常我们在滑到最下面然后 loading 数据的时候可以看到
其他的属性可以在 attrs.xml 中看它的注释来理解,总之一句话,尽量少自己造轮子先看看作者有没有提供接口。