用当前最流行的下拉刷新pullrefresh框架实现类似QQ的下拉刷新功能,下载地址为:https://github.com/chrisbanes/Android-PullToRefresh
我先解释一下下拉刷新涉及的过程:
1、 肯定要有一个下拉头(下拉脚),在这个源码里面LoadingLayout作为下拉头的基类,你可以参照它已经实现的几个样式自定义自己的下拉头,就是对里面显示的内容,动画进行相应的修改。
2、 下拉的过程涉及几个状态,reset,pulltorefresh,refreshing,releasetorefresh等,对应的每个状态分别有不同的动作,源码里面用IPullRefresh接口把相应的动作进行了声明,我们只需要实现它就可以实现相应的动作。
3、 下拉的过程还涉及到下拉头内容的变化,源码中用ILoadingLayout接口对不同状态下的下拉头内容进行了封装。
4、 源码中最重要的基类是PullToRefreshBase,该类封装了下拉刷新的整个过程的功能,但是该类是个抽象类,里面有两个抽象方法分别为isReadyForPullEnd(),isReadyForPullStart();,这两个方法主要是让你根据自己情况进行下拉和上拉的判断。该类也是一个泛型类,可以根据你传入的视图类型生成对应的刷新视图。
5、 源码中PullToRefreshAdapterViewBase类对PullToRefreshBase类进行了封装,故名思议,主要是对AdapterView类型的刷新视图进行的包装,让像ListView,GridView等继承它实现起来更方便。
好了,回到主题,我发现该下拉刷新框架跟QQ的还是有所不一样的,QQ的每次刷新成功都会在下拉头进行提示,而这个刷新完直接回到了初始状态,并没有给出任何提示。
我的实现方法是:
1、在PullToRefreshBase类的内部枚举类State中加了一个刷新成功的状态,
public static enum State {
/**
*When the UI is in a state which means that user is not interacting
*with the Pull-to-Refresh function.
*/
RESET(0x0),
/**
*When the UI is being pulled by the user, but has not been pulled far
*enough so that it refreshes when released.
*/
PULL_TO_REFRESH(0x1),
/**
*When the UI is being pulled by the user, and <strong>has</strong>
*been pulled far enough so that it will refresh when released.
*/
RELEASE_TO_REFRESH(0x2),
REFRESHING_SUCCEED(0x4),//此处是我加的状态,命名可以随意
/**
*When the UI is currently refreshing, caused by a pull gesture.
*/
REFRESHING(0x8),
/**
*When the UI is currently refreshing, caused by a call to
* {@link PullToRefreshBase#setRefreshing() setRefreshing()}.
*/
MANUAL_REFRESHING(0x9),
/**
*When the UI is currently overscrolling, caused by a fling on the
* RefreshableView.
*/
OVERSCROLLING(0x10);
/**
*Maps an int to a specific state. This is needed when saving state.
*
* @param stateInt
* - int to map a State to
* @return State thatstateInt maps to
*/
static State mapIntToValue(final int stateInt) {
for (State value : State.values()) {
if (stateInt == value.getIntValue()) {
return value;
}
}
// If not, returndefault
return RESET;
}
private int mIntValue;
State(int intValue) {
mIntValue = intValue;
}
int getIntValue() {
return mIntValue;
}
}
2、 既然有刷新成功这个状态,肯定要有相关的操作,这里我对ILoadingLayout,以及IPullRefresh进行了修改。
ILoadingLayout: 我添加了一个方法是对刷新成功内容标签进行设置,
public voidsetRefreshingCompleteLable(CharSequence completeLable);
IPullRefresh:我对之前的刷新完成方法进行了修改,通过调用者传入一个变量判断是否刷新成功。
原来的方法:public void onRefreshComplete();
现在的方法:public void setRefreshComplete(booleanisSucceed);
3、 通过修改2之后我们发现很多地方报错,对的,我们这时只需要对报错的地方进行相应的修改即可,这里我们就要对下拉头基类LoadingLayout进行相应的修改了。
(1) 添加了属性刷新成功的字符,以及获取它的资源值
private CharSequence mCompleteLable;
在构造方法中添加如下行,字符串资源值定义为刷新成功
(2) 在该类我添加了如下方法:
public final void refreshSucceed(){
if (null != mHeaderText) {
mHeaderText.setText(mCompleteLable);
}
refreshSucceedImpl();
}
其中这个refreshSucceedImpl为添加的抽象方法,用在具体下拉头中实现。
(3) 分别找到这三个类,在里面实现如下方法,主要用于对刷新成功下来头的显示。
protected void refreshSucceedImpl() {
mHeaderImage.clearAnimation();
mHeaderImage.setVisibility(View.INVISIBLE);
mHeaderProgress.setVisibility(View.GONE);
}
4、 最后我们再来对PullToRefreshBase这个类进行最终的修改,就可以大功告成了。
在这个类中找到onfreshComplete()这个方法,我们改成这样
@Override
public final void setRefreshComplete(booleanisSucceed) {
if (isRefreshing()) {
if (isSucceed) {
setState(State.REFRESHING_SUCCEED);
} else {
setState(State.RESET);
}
}
}
如果是刷新成功则,显示刷新成功,如果是刷新失败,我们直接回到初始状态。
回到setState()方法,我们添加相应的改变
然后我们再去实现onRreshComplete()方法
protected void onRefreshComplete() {
if(mShowViewWhileRefreshing){
switch (mCurrentMode) {
case PULL_FROM_END:
mFooterLayout.refreshSucceed();
break;
case PULL_FROM_START:
mHeaderLayout.refreshSucceed();
break;
default:
// NO-OP
break;
}
}
postDelayed(new Runnable() {
@Override
public void run() {
setState(State.RESET);
}
},500);
}
这里注意一下,postDelayed主要用于显示刷新成功之后回到初始状态,时间设为显示时间,这里我设的是500;
本来以为大工告成,测试的时候发现了一个问题,每次刷新成功显示完后,下拉头的内容先回到初始状态再滑到初始位置,这显然不是我们想看到的,于是我对onreset方法进行了修改:
/**
* Called when the UI has been to be updated tobe in the
* {@linkState#RESET} state.
*/
protected void onReset() {
mIsBeingDragged = false;
mLayoutVisibilityChangesEnabled= true;
//之前是这样的:
/**smoothScrollTo(0);
*mHeaderLayout.reset();
* mFooterLayout.reset();*/
//现在是这样的,在滑动完成之后我们再对下拉内容进行初始化,这样就看不到默认状态了
smoothScrollTo(0,newOnSmoothScrollFinishedListener() {
@Override
public voidonSmoothScrollFinished() {
mHeaderLayout.reset();
mFooterLayout.reset();
}
});
// Always reset both layouts, just in case...
}
5、 我们在刷新完成的逻辑中调用setRefreshComplete(booleanisSucceed)这个方法即可,根据刷新的结果进行传值,结果如下: