用當前最流行的下拉刷新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)這個方法即可,根據刷新的結果進行傳值,結果如下: