android 實現有阻尼下拉/上拉重新整理列表
在上一篇文章《有阻尼下拉重新整理列表的實現》中,我解析瞭如何基於過載dispatchDraw方法重畫子View和過載onTouchEvent方法監控受試來實現下拉重新整理列表,而在這篇文章中,我將會基於上一篇文章介紹的技術,在下拉重新整理列表PullToRefreshListVIew的基礎上,加上有阻尼上拉重新整理功能。上一篇文章《有阻尼下拉重新整理列表的實現》的連結如下。
http://blog.csdn.net/ivan_zgj/article/details/50664780
好,我們還是先來看看效果。
1. 通過onScrollListener監控listVIew是否滾動到底部
在PullToRefreshListView中,我們通過onScrollListener回撥來監控PullToRefreshListView是否已經滾動到頂部,當時的程式碼是這樣的:
當時我們通過判斷firstVisibleItem==0以及第一個子View是否完全可見,從而確定PullToRefreshListView是否滾動到頂部。現在,我們加入以下程式碼來判斷PullToRefreshListView是否滾動到底部。setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // 沒有子view的時候(沒有資料,或者被拉到看不到子view),意味著該listView滾動到頂部 if (getChildCount() == 0) { isTop = true; return; } if (firstVisibleItem == 0) { View firstView = getChildAt(0); if (firstView.getTop() + distanceY >= 0) { // 第一個view可見且其相對parent(該listView)的頂部距離大於等於0,意味著該listView也是滾動到頂部 isTop = true; return; } } isTop = false; } });
在onScroll方法中,fisrstVisibleItem是指列表當前可見的第一個子View在其adapter中的position,而visibleItemCount是指可見的子View的個數,totalItemCount是指adapter總共有多少個View。因此,我們可以很容易得出結論,當:if (firstVisibleItem + visibleItemCount == totalItemCount) { View firstView = getChildAt(visibleItemCount - 1); if (firstView.getBottom() + distanceY <= getHeight()) { // 最後一個view可見且其相對parent(該listView)的底部距離小於等於listView高度,意味著該listView也是滾動到底部 isBottom = true; return; } } isBottom = false;
firstVisibleItem + visibleItemCount == totalItemCount
成立時,PullToRefreshListView就已經滾動到底部了。
2. 監控滑動手勢使listView進入上拉狀態
在PullToRefreshListView中,我們通過過載onTouchEvent方法來監控使用者手勢,從而判斷PullToRefreshListView是否要進行下拉,當時的程式碼是這樣的:
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
// 按下的時候
lastAction = MotionEvent.ACTION_DOWN;
cancelAnimating();
L.d(TAG, "touch down");
} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
// 放開手指,開始回滾
isPulling = false;
lastAction = -1;
startAnimating();
L.d(TAG, "touch up");
} else if (lastAction == MotionEvent.ACTION_DOWN) {
if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
// 在按下手指的基礎上,開始滑動
if (isTop && !isPulling) {
// listView在頂部而且不處於下拉重新整理狀態,開始下拉
pullStartY = ev.getY();
lastAction = MotionEvent.ACTION_MOVE;
isPulling = true;
}
}
} else if (lastAction == MotionEvent.ACTION_MOVE) {
if (isTop) {
// 下拉
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY > 0) {
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
// 在下拉狀態時取消系統對move動作的響應,完全由本類響應
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// 在下拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統進行響應
ev.setAction(MotionEvent.ACTION_MOVE);
}
} else {
// 在下拉過程中往上拉動listView使listView往下滾動到其沒有滾動到頂部,則取消其下拉狀態,回到手指按下的初始狀態
lastAction = MotionEvent.ACTION_DOWN;
isPulling = false;
distanceY = 0;
}
}
return super.onTouchEvent(ev);
}
現在,我們只需要在lastAction == MotionEvent.ACTION_MOVE判斷裡面,與isTop判斷並列,再加一個判斷。
if (isBottom) {
// 上拉
configureHeader(false);
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY < 0) {
distanceY = (float) (Math.exp(-pullStartY / ev.getY() / 40) * distanceY);
// 在上拉狀態時取消系統對move動作的響應,完全由本類響應
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// 在上拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統進行響應
ev.setAction(MotionEvent.ACTION_MOVE);
}
}
很明顯,這個判斷是在執行這樣一個動作,如果PullToRefreshListView已經滾動到底部,那麼就根據使用者手指滑動的距離計算PullToRefreshListView上拉的距離,這一段程式碼與處理下拉的程式碼是基本一樣的。
3. 過載dispatchDraw方法實現上拉
在PullToRefreshListView的基礎上,我們將重畫下拉的子View的程式碼替換成以下程式碼。
// 重畫子view
int left = getPaddingLeft();
int top = getPaddingTop();
int bottom = getPaddingBottom();
canvas.save();
if (distanceY > 0) {
canvas.translate(left, top + distanceY);
} else {
canvas.translate(left, -bottom + distanceY);
}
for (int i=0;i<getChildCount();i++) {
View child = getChildAt(i);
drawChild(canvas, child, getDrawingTime());
}
canvas.restore();
這裡只需要注意下拉和上拉的時候canvas要translate的方向和距離的計算就可以了,原理在上一篇文章中已經解析過了,這裡就不多說了。大家結合著看就好了。
4. 加上重新整理頭
為了優化UI和給使用者做出提示,我這次還加入重新整理頭,就是那個提示下拉重新整理,釋放以重新整理blablabla的東西。同樣的,我也是在dispatchDraw方法裡面實現的。具體程式碼如下。
canvas.save();
// 畫重新整理頭
View header;
if (distanceY > 0) {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad(true));
if (distanceY > whereToLoad) {
topRefreshHeaderView.setText(HeaderView.STATE_CAN_RELEASE);
topRefreshHeaderView.setIcon(HeaderView.STATE_CAN_RELEASE);
} else if (distanceY < whereToLoad) {
topRefreshHeaderView.setText(HeaderView.STATE_PULLING_DOWN);
topRefreshHeaderView.setIcon(HeaderView.STATE_PULLING_DOWN);
}
header = topRefreshHeaderView.getView();
canvas.translate(left, top + distanceY - header.getHeight() - offset);
} else {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad(false));
if (-distanceY > whereToLoad) {
bottomRefreshHeaderView.setText(HeaderView.STATE_CAN_RELEASE);
bottomRefreshHeaderView.setIcon(HeaderView.STATE_CAN_RELEASE);
} else if (-distanceY < whereToLoad) {
bottomRefreshHeaderView.setText(HeaderView.STATE_PULLING_UP);
bottomRefreshHeaderView.setIcon(HeaderView.STATE_PULLING_UP);
}
header = bottomRefreshHeaderView.getView();
canvas.translate(left, -bottom + distanceY + getHeight() + offset);
}
drawChild(canvas, header, getDrawingTime());
canvas.restore();
我們看到這裡有兩個判斷,第一個是下拉重新整理頭,第二個是上拉重新整理頭,其實原理也是一樣,將canvas平移到合適的位置,然後呼叫drawChild方法就可以了。
這裡要簡單地說一說topRefreshHeaderView和bottomRefreshHeaderView這兩個東西,其實它們是我設計的一個抽象類實現物件,該抽象類如下。
/**
* 重新整理頭的抽象類
*/
public abstract class HeaderView {
private View headerView;
public static final int STATE_PULLING_UP = 0x30;
public static final int STATE_PULLING_DOWN = 0x31;
public static final int STATE_CAN_RELEASE = 0x32;
public static final int STATE_REFRESHING = 0x33;
public HeaderView(View headerView) {
this.headerView = headerView;
}
/**
* 獲得重新整理頭的View
* @return 例項化是給予的一個自定義View
*/
protected View getView() {
return headerView;
}
/**
* 根據狀態設定顯示內容
* @param state 狀態
*/
protected abstract void setText(int state);
/**
* 根據狀態設定顯示圖示
* @param state 狀態
*/
protected abstract void setIcon(int state);
}
根據這個抽象類的設計,我們可以知道,該抽象類為重新整理頭的外觀提供了一個標準,它應該有一個圖示和一個提示的文字內容。當然,PullToRefreshListView有一個預設的重新整理頭。
最後就是大家最喜歡的原始碼了。
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;
import com.ivan.healthcare.healthcare_android.log.L;
/**
* 支援下拉重新整理的的listView
* Created by Ivan on 16/2/14.
*/
public class PullToRefreshListView extends ListView {
private final String TAG = "PullToRefreshListView";
/**
* 預設回滾速度,millis/100dp
*/
private final int DEFAULT_BASE_ANIMATING_TIME_PER_100DP = 100;
/**
* 預設重新整理背景高度
*/
public static final int DEFAULT_WHERE_TO_LOAD = 80;
/**
* 記錄上一個手勢動作
*/
private int lastAction = -1;
/**
* 下拉起始位置
*/
private float pullStartY = -1;
/**
* 是否處於“滾動到頂部”狀態
*/
private boolean isTop = true;
/**
* 是否處於“滾動到底部”狀態
*/
private boolean isBottom = true;
/**
* 下拉距離
*/
private float distanceY = 0;
/**
* 是否處於下拉狀態
*/
private boolean isPulling = false;
/**
* 回滾動畫控制器
*/
private ValueAnimator pullCancelAnimator;
private Context context;
/**
* 重新整理背景
*/
private Drawable refreshDrawable;
/**
* 下拉重新整理頭
*/
private HeaderView topRefreshHeaderView;
/**
* 上拉重新整理頭
*/
private HeaderView bottomRefreshHeaderView;
/**
* 重新整理頭位置偏移
*/
private int offset;
/**
* 重新整理回撥
*/
private OnLoadCallBack onLoadCallBack = new OnLoadCallBack(this) {
@Override
public void onLoad(boolean topOrBottom) {
}
@Override
public void cancelLoad(boolean topOrBottom) {
}
};
public PullToRefreshListView(Context context) {
super(context);
initView(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
this.context = context;
offset = dp2px(10);
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// 沒有子view的時候(沒有資料,或者被拉到看不到子view),意味著該listView滾動到頂部/底部
if (getChildCount() == 0) {
isTop = true;
isBottom = true;
return;
}
if (firstVisibleItem == 0) {
View firstView = getChildAt(0);
if (firstView.getTop() + distanceY >= 0) {
// 第一個view可見且其相對parent(該listView)的頂部距離大於等於0,意味著該listView也是滾動到頂部
isTop = true;
return;
}
}
isTop = false;
if (firstVisibleItem + visibleItemCount == totalItemCount) {
View firstView = getChildAt(visibleItemCount - 1);
if (firstView.getBottom() + distanceY <= getHeight()) {
// 最後一個view可見且其相對parent(該listView)的底部距離小於等於listView高度,意味著該listView也是滾動到底部
isBottom = true;
return;
}
}
isBottom = false;
}
});
}
/**
* 配置重新整理頭,當開始下拉/上拉時會執行該方法
* @param topOrBottom true for top, false for bottom
*/
private void configureHeader(boolean topOrBottom) {
final TextView header;
if (topOrBottom) {
if (topRefreshHeaderView == null) {
topRefreshHeaderView = onLoadCallBack.getHeaderView(true);
if (topRefreshHeaderView != null) {
return;
}
header = new TextView(context);
topRefreshHeaderView = new HeaderView(header) {
@Override
public void setText(int state) {
switch (state) {
case STATE_PULLING_DOWN:
header.setText("下拉重新整理");
break;
case STATE_PULLING_UP:
header.setText("上拉重新整理");
break;
case STATE_CAN_RELEASE:
header.setText("釋放以重新整理");
break;
case STATE_REFRESHING:
header.setText("重新整理中...");
break;
default:
break;
}
}
@Override
public void setIcon(int state) {
}
};
} else {
return;
}
header.setText("下拉重新整理");
} else {
if (bottomRefreshHeaderView == null) {
bottomRefreshHeaderView = onLoadCallBack.getHeaderView(true);
if (bottomRefreshHeaderView != null) {
return;
}
header = new TextView(context);
bottomRefreshHeaderView = new HeaderView(header) {
@Override
public void setText(int state) {
switch (state) {
case STATE_PULLING_DOWN:
header.setText("下拉重新整理");
break;
case STATE_PULLING_UP:
header.setText("上拉重新整理");
break;
case STATE_CAN_RELEASE:
header.setText("釋放以重新整理");
break;
case STATE_REFRESHING:
header.setText("重新整理中...");
break;
default:
break;
}
}
@Override
public void setIcon(int state) {
}
};
} else {
return;
}
header.setText("上拉重新整理");
}
header.setTextSize(20);
header.setTextColor(Color.WHITE);
header.setGravity(Gravity.CENTER);
LayoutParams layoutParams = (LayoutParams) header.getLayoutParams();
if (layoutParams == null) {
layoutParams = (LayoutParams) generateDefaultLayoutParams();
header.setLayoutParams(layoutParams);
}
int heightMode = MeasureSpec.getMode(layoutParams.height);
int heightSize = MeasureSpec.getSize(layoutParams.height);
if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;
int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();
if (heightSize > maxHeight) heightSize = maxHeight;
// measure & layout
int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);
int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
header.measure(ws, hs);
header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
// 按下的時候
lastAction = MotionEvent.ACTION_DOWN;
cancelAnimating();
L.d(TAG, "touch down");
} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
// 放開手指,開始回滾
isPulling = false;
lastAction = -1;
startAnimating(distanceY>0);
L.d(TAG, "touch up");
} else if (lastAction == MotionEvent.ACTION_DOWN) {
if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
// 在按下手指的基礎上,開始滑動
if ((isBottom || isTop) && !isPulling) {
// listView在頂部/底部而且不處於下拉重新整理狀態,開始下拉/上拉
pullStartY = ev.getY();
lastAction = MotionEvent.ACTION_MOVE;
isPulling = true;
}
}
} else if (lastAction == MotionEvent.ACTION_MOVE) {
if (isTop) {
// 下拉
configureHeader(true);
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY > 0) {
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
// 在下拉狀態時取消系統對move動作的響應,完全由本類響應
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// 在下拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統進行響應
ev.setAction(MotionEvent.ACTION_MOVE);
}
}
if (isBottom) {
// 上拉
configureHeader(false);
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY < 0) {
distanceY = (float) (Math.exp(-pullStartY / ev.getY() / 40) * distanceY);
// 在上拉狀態時取消系統對move動作的響應,完全由本類響應
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// 在上拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統進行響應
ev.setAction(MotionEvent.ACTION_MOVE);
}
}
if (!isTop && !isBottom){
// 在下拉過程中往上拉動listView使listView往下滾動到其沒有滾動到頂部,則取消其下拉狀態,回到手指按下的初始狀態
lastAction = MotionEvent.ACTION_DOWN;
isPulling = false;
distanceY = 0;
}
}
return super.onTouchEvent(ev);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (distanceY != 0) {
if (refreshDrawable == null) {
refreshDrawable = onLoadCallBack.refreshDrawable();
}
if (refreshDrawable == null) {
canvas.drawColor(Color.GRAY);
} else {
int left = getPaddingLeft();
int top = getPaddingTop();
refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);
refreshDrawable.draw(canvas);
}
// 重畫子view
int left = getPaddingLeft();
int top = getPaddingTop();
int bottom = getPaddingBottom();
canvas.save();
if (distanceY > 0) {
canvas.translate(left, top + distanceY);
} else {
canvas.translate(left, -bottom + distanceY);
}
for (int i=0;i<getChildCount();i++) {
View child = getChildAt(i);
drawChild(canvas, child, getDrawingTime());
}
canvas.restore();
canvas.save();
// 畫重新整理頭
View header;
if (distanceY > 0) {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad(true));
if (distanceY > whereToLoad) {
topRefreshHeaderView.setText(HeaderView.STATE_CAN_RELEASE);
topRefreshHeaderView.setIcon(HeaderView.STATE_CAN_RELEASE);
} else if (distanceY < whereToLoad) {
topRefreshHeaderView.setText(HeaderView.STATE_PULLING_DOWN);
topRefreshHeaderView.setIcon(HeaderView.STATE_PULLING_DOWN);
}
header = topRefreshHeaderView.getView();
canvas.translate(left, top + distanceY - header.getHeight() - offset);
} else {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad(false));
if (-distanceY > whereToLoad) {
bottomRefreshHeaderView.setText(HeaderView.STATE_CAN_RELEASE);
bottomRefreshHeaderView.setIcon(HeaderView.STATE_CAN_RELEASE);
} else if (-distanceY < whereToLoad) {
bottomRefreshHeaderView.setText(HeaderView.STATE_PULLING_UP);
bottomRefreshHeaderView.setIcon(HeaderView.STATE_PULLING_UP);
}
header = bottomRefreshHeaderView.getView();
canvas.translate(left, -bottom + distanceY + getHeight() + offset);
}
drawChild(canvas, header, getDrawingTime());
canvas.restore();
}
}
/**
* 下拉結束時進行回滾動畫並執行重新整理動作
* @param topOrBottom true for top, false for bottom
*/
private void startAnimating(final boolean topOrBottom) {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad(topOrBottom));
final boolean toLoad;
if (distanceY > whereToLoad && topOrBottom) {
// 下拉
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);
toLoad = true;
} else if (-distanceY > whereToLoad && !topOrBottom) {
// 上拉
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, -whereToLoad);
toLoad = true;
} else {
// 回滾
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);
toLoad = false;
}
pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(Math.abs(distanceY))/100));
pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
distanceY = (float) animation.getAnimatedValue();
ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);
}
});
pullCancelAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
post(new Runnable() {
@Override
public void run() {
if (topOrBottom) {
topRefreshHeaderView.setText(HeaderView.STATE_REFRESHING);
topRefreshHeaderView.setIcon(HeaderView.STATE_REFRESHING);
} else {
bottomRefreshHeaderView.setText(HeaderView.STATE_REFRESHING);
bottomRefreshHeaderView.setIcon(HeaderView.STATE_REFRESHING);
}
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.onLoad(topOrBottom);
}
}
});
}
@Override
public void onAnimationCancel(Animator animation) {
post(new Runnable() {
@Override
public void run() {
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.cancelLoad(topOrBottom);
}
}
});
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
pullCancelAnimator.start();
}
/**
* 取消回滾動畫
*/
private void cancelAnimating() {
if (pullCancelAnimator != null) {
pullCancelAnimator.cancel();
}
}
private float px2dp(float pxvalue) {
return (pxvalue - 0.5f) /context.getResources().getDisplayMetrics().density;
}
private int dp2px(float dpvalue) {
return (int) (dpvalue * context.getResources().getDisplayMetrics().density + 0.5f);
}
/**
* 下拉重新整理的回撥
*/
public static abstract class OnLoadCallBack {
private PullToRefreshListView listView;
public OnLoadCallBack(PullToRefreshListView lv) {
this.listView = lv;
}
/**
* 下拉結束後將listView定位到哪個位置等待重新整理完成
* @param topOrBottom true for top, false for bottom
* @return listView的定位y座標值,in dp
*/
public int whereToLoad(boolean topOrBottom) {
return DEFAULT_WHERE_TO_LOAD;
}
/**
* 下拉結束後進行重新整理的回撥
* @param topOrBottom true for top, false for bottom
*/
public abstract void onLoad(boolean topOrBottom);
/**
* 取消重新整理
* @param topOrBottom true for top, false for bottom
*/
public abstract void cancelLoad(boolean topOrBottom);
/**
* 下拉重新整理的背景
* @return 背景drawable
*/
public Drawable refreshDrawable() {
return new ColorDrawable(Color.GRAY);
}
/**
* 自定義重新整理頭
* @param topOrBottom true for top, false for bottom
*/
public HeaderView getHeaderView(boolean topOrBottom) {
if (topOrBottom) {
listView.destroyTopRefreshHeaderView();
} else {
listView.destroyBottomRefreshHeaderView();
}
return null;
}
}
/**
* 設定下拉重新整理回撥
* @param cb 回撥
*/
public void setOnLoadCallBack(OnLoadCallBack cb) {
this.onLoadCallBack = cb;
}
/**
* 重新整理動作結束後呼叫該方法結束重新整理,使得listView回滾到頂部
*/
public void setLoadingFinish() {
startAnimating(distanceY>0);
}
/**
* 重新整理頭的抽象類
*/
public abstract class HeaderView {
private View headerView;
public static final int STATE_PULLING_UP = 0x30;
public static final int STATE_PULLING_DOWN = 0x31;
public static final int STATE_CAN_RELEASE = 0x32;
public static final int STATE_REFRESHING = 0x33;
public HeaderView(View headerView) {
this.headerView = headerView;
}
/**
* 獲得重新整理頭的View
* @return 例項化是給予的一個自定義View
*/
protected View getView() {
return headerView;
}
/**
* 根據狀態設定顯示內容
* @param state 狀態
*/
protected abstract void setText(int state);
/**
* 根據狀態設定顯示圖示
* @param state 狀態
*/
protected abstract void setIcon(int state);
}
protected void destroyTopRefreshHeaderView() {
topRefreshHeaderView = null;
}
protected void destroyBottomRefreshHeaderView() {
bottomRefreshHeaderView = null;
}
}