Android ListView 實現下拉重新整理上拉載入
阿新 • • 發佈:2019-01-04
1.簡介
無疑,在Android開發中,ListView是使用非常頻繁的控制元件之一,ListView提供一個列表的容易,允許我們以列表的形式將資料展示到介面上,但是Google給我們提供的原生ListView的控制元件,雖然在功能上很強大,但是在使用者體驗和動態效果上,還是比較差勁的。為了改善使用者體驗,市面上紛紛出現了各種各樣的自定義的ListView,他們功能強大,介面美觀,使我們該需要學習的地方。其中,使用最頻繁的功能無疑就是ListView的下拉重新整理和上拉載入資料了,幾乎在沒一款內容型的App中都可以找到這種控制元件的身影,尤其是需要聯網獲取資料的模組,使用的就更為頻繁了,so,我們很有必要了解下這種效果是怎麼實現的。
2.開源元件PullToRefreshList介紹
既然Android和Java都是開源的,一些常見的功能或者效果就不難被找到。PullToRefresh就是一個典型的例子,PullToRefresh是老外寫的一個開源ListView元件,這個專案在ListView的基礎上擴充套件了ListView的功能,增強了Listview的使用者體驗,功能十分強大,而且很容易被整合到當前的專案中,你只需要呼叫簡單的API,即可省去很多不必要的麻煩,非常棒。以上是專案在Github的連結,有興趣的可以戳進去down下來,使用一下。這裡不是我們的重點,不想廢話了。3.自定義ListView——下拉重新整理&上拉載入
好,效果圖如上所示,下面逐步講解下實現的過程。首先,來觀察一下,ListView上方的佈局,我這裡稱其為“頭佈局”,這個所謂的頭佈局,大致功能是這樣的,一個ImageView顯示上下拉動方向的狀態的,ImageView相同的位置隱藏了一個ProgressBar,用來在資料重新整理時給個提示作用的。還有兩個TextView,上面用來顯示下拉重新整理時提醒使用者是如何操作的,例如“下拉重新整理”“鬆開重新整理”“正在重新整理”,另一個是用來顯示本次重新整理的時間的。比較簡單的佈局,下面是XML程式碼: [html]
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dip">
- <ImageView
- android:id="@+id/iv_listview_header_arrow"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:minWidth="30dip"
- android:src="@drawable/common_listview_headview_red_arrow"/>
- <ProgressBar
- android:id="@+id/pb_listview_header"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:indeterminateDrawable="@drawable/common_progressbar"
- android:visibility="gone"/>
- </FrameLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="center_horizontal"
- android:orientation="vertical">
- <TextView
- android:id="@+id/tv_listview_header_state"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="下拉重新整理"
- android:textColor="#FF0000"
- android:textSize="18sp"/>
- <TextView
- android:id="@+id/tv_listview_header_last_update_time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dip"
- android:text="最後重新整理時間: 2014-10-10 12:56:12"
- android:textColor="@android:color/white"
- android:textSize="14sp"/>
- </LinearLayout>
- </LinearLayout>
<?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="wrap_content"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip" >
<ImageView
android:id="@+id/iv_listview_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="30dip"
android:src="@drawable/common_listview_headview_red_arrow" />
<ProgressBar
android:id="@+id/pb_listview_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/common_progressbar"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_listview_header_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉重新整理"
android:textColor="#FF0000"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_listview_header_last_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:text="最後重新整理時間: 2014-10-10 12:56:12"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
下面講解一下ListView下方的佈局,我稱其為“腳佈局”,這個腳佈局就更簡單了,直接看XML程式碼好了:
[html]
view plaincopyprint?
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_margin="10dip"
- android:gravity="center_vertical"
- android:orientation="horizontal">
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:indeterminateDrawable="@drawable/common_progressbar"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="10dip"
- android:text="載入更多..."
- android:textColor="#FF0000"
- android:textSize="18sp"/>
- </LinearLayout>
- </LinearLayout>
<?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="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="10dip"
android:gravity="center_vertical"
android:orientation="horizontal" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/common_progressbar" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="載入更多..."
android:textColor="#FF0000"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
此外,兩個佈局都用到一個ProgressBar的背景,其XML如下:
[html]
view plaincopyprint?
- <?xmlversion="1.0"encoding="utf-8"?>
- <rotatexmlns:android="http://schemas.android.com/apk/res/android"
- android:fromDegrees="0"
- android:pivotX="50%"
- android:pivotY="50%"
- android:toDegrees="360">
- <shape
- android:innerRadiusRatio="3"
- android:shape="ring"
- android:useLevel="false">
- <gradient
- android:centerColor="#FF6666"
- android:endColor="#FF0000"
- android:startColor="#FFFFFF"
- android:type="sweep"/>
- </shape>
- </rotate>
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:useLevel="false" >
<gradient
android:centerColor="#FF6666"
android:endColor="#FF0000"
android:startColor="#FFFFFF"
android:type="sweep" />
</shape>
</rotate>
ListView的頭佈局和腳佈局已經做好了,那麼接下來該怎麼整合到ListView上去呢?首先我們來看看ListView的部分原始碼,很輕鬆能找到這兩個方法:addHeaderView(View v);addFooterView(View v),通過字面的意思就可以理解,這兩個方法分別是向ListView頂部新增一個View和向ListView的底部新增View的,有了這兩個方法,那麼上面的頭佈局和腳佈局就很容易被新增到ListView上了,並且成為ListView的一體。
其實,再看會發現,簡單的使用這兩個方法分別往ListView上新增頭佈局和腳佈局是不合理,新增上去的頭佈局和腳佈局會被顯示出來,並沒有被隱藏掉,為了實現下拉和上拉時能夠將頭佈局和腳佈局都“拉出來”並且還可以鬆開時,再次隱藏起來,我們可以使用View下的一個方法setPadding(int left, int top, int right, int bottom),這個方法設定View的Padding屬性,這裡,我們不必管left、right、bottom,只要設定top的值為頭佈局或者腳佈局的高度即可“隱藏”這兩個佈局,而且還可以在手指滑動螢幕的時候,動態的設定這個top的值,來實現頭佈局和腳佈局的顯示-隱藏-顯示。
還有一個非常重要的話題,就是這個top的值還設定為多少合適?上面說了,我們來頭佈局來說明一下,隱藏這個頭佈局需要將top值設定成top=- 頭佈局高度,那麼這個頭佈局的高度怎麼求得呢?很顯然,使用getHeight()是得不到頭佈局高度的,因為getHeight()方法是先控制元件在螢幕上展示完畢後得到的高度,顯然在這裡,這個ListView還在構建中,並沒有展示到螢幕上。所以注意了,我們先呼叫View下的measure(int
widthMeasureSpec, int heightMeasureSpec)方法,將widthMeasureSpec和heightMeasureSpec分別設定為0,這裡的widthMeasureSpec和heightMeasureSpec並不是一個準備的值,而且指定一個規格或者標準讓系統幫我們測量View的寬高,當我們指定widthMeasureSpec和heightMeasureSpec分別為0的時候,系統將不採用這個規格去測量,而是根據實際情況去測量。之後,我們可以呼叫View下的getMeasuredHeight()方法獲取真實的頭佈局的高度,然後設定top
= - 頭佈局實際高度,實現隱藏頭佈局。
[java]
view plaincopyprint?
- publicclass RefreshListView extends ListView implements OnScrollListener {
- privatestaticfinal String TAG = "RefreshListView";
- privateint firstVisibleItemPosition; // 螢幕顯示在第一個的item的索引
- privateint downY; // 按下時y軸的偏移量
- privateint headerViewHeight; // 頭佈局的高度
- private View headerView; // 頭佈局的物件
- privatefinalint DOWN_PULL_REFRESH = 0; // 下拉重新整理狀態
- privatefinalint RELEASE_REFRESH = 1; // 鬆開重新整理
- privatefinalint REFRESHING = 2; // 正在重新整理中
- privateint currentState = DOWN_PULL_REFRESH; // 頭佈局的狀態: 預設為下拉重新整理狀態
- private Animation upAnimation; // 向上旋轉的動畫
- private Animation downAnimation; // 向下旋轉的動畫
- private ImageView ivArrow; // 頭佈局的剪頭
- private ProgressBar mProgressBar; // 頭佈局的進度條
- private TextView tvState; // 頭佈局的狀態
- private TextView tvLastUpdateTime; // 頭佈局的最後更新時間
- private OnRefreshListener mOnRefershListener;
- privateboolean isScrollToBottom; // 是否滑動到底部
- private View footerView; // 腳佈局的物件
- privateint footerViewHeight; // 腳佈局的高度
- privateboolean isLoadingMore = false; // 是否正在載入更多中
- public RefreshListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initHeaderView();
- initFooterView();
- this.setOnScrollListener(this);
- }
- /**
- * 初始化腳佈局
- */
- privatevoid initFooterView() {
- footerView = View.inflate(getContext(), R.layout.listview_footer, null);
- footerView.measure(0, 0);
- footerViewHeight = footerView.getMeasuredHeight();
- footerView.setPadding(0, -footerViewHeight, 0, 0);
- this.addFooterView(footerView);
- }
- /**
- * 初始化頭佈局
- */
- privatevoid initHeaderView() {
- headerView = View.inflate(getContext(), R.layout.listview_header, null);
- ivArrow = (ImageView) headerView
- .findViewById(R.id.iv_listview_header_arrow);
- mProgressBar = (ProgressBar) headerView
- .findViewById(R.id.pb_listview_header);
- tvState = (TextView) headerView
- .findViewById(R.id.tv_listview_header_state);
- tvLastUpdateTime = (TextView) headerView
- .findViewById(R.id.tv_listview_header_last_update_time);
- // 設定最後重新整理時間
- tvLastUpdateTime.setText("最後重新整理時間: " + getLastUpdateTime());
- headerView.measure(0, 0); // 系統會幫我們測量出headerView的高度
- headerViewHeight = headerView.getMeasuredHeight();
- headerView.setPadding(0, -headerViewHeight, 0, 0);
- this.addHeaderView(headerView); // 向ListView的頂部新增一個view物件
- initAnimation();
- }
- /**
- * 獲得系統的最新時間
- *
- * @return
- */
- private String getLastUpdateTime() {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- return sdf.format(System.currentTimeMillis());
- }
- /**
- * 初始化動畫
- */
- privatevoid initAnimation() {
- upAnimation = new RotateAnimation(0f, -180f,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
- 0.5f);
- upAnimation.setDuration(500);
- upAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上
- downAnimation = new RotateAnimation(-180f, -360f,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
- 0.5f);
- downAnimation.setDuration(500);
- downAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上
- }
- @Override
- publicboolean onTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN :
- downY = (int) ev.getY();
- break;
- case MotionEvent.ACTION_MOVE :
- int moveY = (int) ev.getY();
- // 移動中的y - 按下的y = 間距.
- int diff = (moveY - downY) / 2;
- // -頭佈局的高度 + 間距 = paddingTop
- int paddingTop = -headerViewHeight + diff;
- // 如果: -頭佈局的高度 > paddingTop的值 執行super.onTouchEvent(ev);
- if (firstVisibleItemPosition == 0
- && -headerViewHeight < paddingTop) {
- if (paddingTop > 0 && currentState == DOWN_PULL_REFRESH) { // 完全顯示了.
- Log.i(TAG, "鬆開重新整理");
- currentState = RELEASE_REFRESH;
- refreshHeaderView();
- } elseif (paddingTop < 0
- && currentState == RELEASE_REFRESH) { // 沒有顯示完全
- Log.i(TAG, "下拉重新整理");
- currentState = DOWN_PULL_REFRESH;
- refreshHeaderView();
- }
- // 下拉頭佈局
- headerView.setPadding(0, paddingTop, 0, 0);
- returntrue;
- }
- break;
- case MotionEvent.ACTION_UP :
- // 判斷當前的狀態是鬆開重新整理還是下拉重新整理
- if (currentState == RELEASE_REFRESH) {
- Log.i(TAG, "重新整理資料.");
- // 把頭佈局設定為完全顯示狀態
- headerView.setPadding(0, 0, 0, 0);
- // 進入到正在重新整理中狀態
- currentState = REFRESHING;
- refreshHeaderView();
- if (mOnRefershListener != null) {
- mOnRefershListener.onDownPullRefresh(); // 呼叫使用者的監聽方法
- }
- } elseif (currentState == DOWN_PULL_REFRESH) {
- // 隱藏頭佈局
- headerView.setPadding(0, -headerViewHeight, 0, 0);
- }
- break;
- default :
- break;
- }
- returnsuper.onTouchEvent(ev);
- }
- /**
- * 根據currentState重新整理頭佈局的狀態
- */
- privatevoid refreshHeaderView() {
- switch (currentState) {
- case DOWN_PULL_REFRESH : // 下拉重新整理狀態
- tvState.setText("下拉重新整理");
- ivArrow.startAnimation(downAnimation); // 執行向下旋轉
- break;
- case RELEASE_REFRESH : // 鬆開重新整理狀態
- tvState.setText("鬆開重新整理");
- ivArrow.startAnimation(upAnimation); // 執行向上旋轉
- break;
- case REFRESHING : // 正在重新整理中狀態
- ivArrow.clearAnimation();
- ivArrow.setVisibility(View.GONE);
- mProgressBar.setVisibility(View.VISIBLE);
- tvState.setText("正在重新整理中...");
- break;
- default :
- break;
- }
- }
- /**
- * 當滾動狀態改變時回撥
- */
- @Override
- publicvoid onScrollStateChanged(AbsListView view, int scrollState) {
- if (scrollState == SCROLL_STATE_IDLE
- || scrollState == SCROLL_STATE_FLING) {
- // 判斷當前是否已經到了底部
- if (isScrollToBottom && !isLoadingMore) {
- isLoadingMore = true;
- // 當前到底部
- Log.i(TAG, "載入更多資料");
- footerView.setPadding(0, 0, 0, 0);
- this.setSelection(this.getCount());
- if (mOnRefershListener != null) {
- mOnRefershListener.onLoadingMore();
- }
- }
- }
- }
- /**
- * 當滾動時呼叫
- *
- * @param firstVisibleItem
- * 當前螢幕顯示在頂部的item的position
- * @param visibleItemCount
- * 當前螢幕顯示了多少個條目的總數
- * @param totalItemCount
- * ListView的總條目的總數
- */
- @Override
- publicvoid onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- firstVisibleItemPosition = firstVisibleItem;
- if (getLastVisiblePosition() == (totalItemCount - 1)) {
- isScrollToBottom = true;
- } else {
- isScrollToBottom = false;
- }
- }
- /**
- * 設定重新整理監聽事件
- *
- * @param listener
- */
- publicvoid setOnRefreshListener(OnRefreshListener listener) {
- mOnRefershListener = listener;
- }
- /**
- * 隱藏頭佈局
- */
- publicvoid hideHeaderView() {
- headerView.setPadding(0, -headerViewHeight, 0, 0);
- ivArrow.setVisibility(View.VISIBLE);
- mProgressBar.setVisibility(View.GONE);
- tvState.setText("下拉重新整理");
- tvLastUpdateTime.setText("最後重新整理時間: " + getLastUpdateTime());
- currentState = DOWN_PULL_REFRESH;
- }
- /**
- * 隱藏腳佈局
- */
- publicvoid hideFooterView() {
- footerView.setPadding(0, -footerViewHeight, 0, 0);
- isLoadingMore = false;
- }
- }
public class RefreshListView extends ListView implements OnScrollListener {
private static final String TAG = "RefreshListView";
private int firstVisibleItemPosition; // 螢幕顯示在第一個的item的索引
private int downY; // 按下時y軸的偏移量
private int headerViewHeight; // 頭佈局的高度
private View headerView; // 頭佈局的物件
private final int DOWN_PULL_REFRESH = 0; // 下拉重新整理狀態
private final int RELEASE_REFRESH = 1; // 鬆開重新整理
private final int REFRESHING = 2; // 正在重新整理中
private int currentState = DOWN_PULL_REFRESH; // 頭佈局的狀態: 預設為下拉重新整理狀態
private Animation upAnimation; // 向上旋轉的動畫
private Animation downAnimation; // 向下旋轉的動畫
private ImageView ivArrow; // 頭佈局的剪頭
private ProgressBar mProgressBar; // 頭佈局的進度條
private TextView tvState; // 頭佈局的狀態
private TextView tvLastUpdateTime; // 頭佈局的最後更新時間
private OnRefreshListener mOnRefershListener;
private boolean isScrollToBottom; // 是否滑動到底部
private View footerView; // 腳佈局的物件
private int footerViewHeight; // 腳佈局的高度
private boolean isLoadingMore = false; // 是否正在載入更多中
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
this.setOnScrollListener(this);
}
/**
* 初始化腳佈局
*/
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.listview_footer, null);
footerView.measure(0, 0);
footerViewHeight = footerView.getMeasuredHeight();
footerView.setPadding(0, -footerViewHeight, 0, 0);
this.addFooterView(footerView);
}
/**
* 初始化頭佈局
*/
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.listview_header, null);
ivArrow = (ImageView) headerView
.findViewById(R.id.iv_listview_header_arrow);
mProgressBar = (ProgressBar) headerView
.findViewById(R.id.pb_listview_header);
tvState = (TextView) headerView
.findViewById(R.id.tv_listview_header_state);
tvLastUpdateTime = (TextView) headerView
.findViewById(R.id.tv_listview_header_last_update_time);
// 設定最後重新整理時間
tvLastUpdateTime.setText("最後重新整理時間: " + getLastUpdateTime());
headerView.measure(0, 0); // 系統會幫我們測量出headerView的高度
headerViewHeight = headerView.getMeasuredHeight();
headerView.setPadding(0, -headerViewHeight, 0, 0);
this.addHeaderView(headerView); // 向ListView的頂部新增一個view物件
initAnimation();
}
/**
* 獲得系統的最新時間
*
* @return
*/
private String getLastUpdateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(System.currentTimeMillis());
}
/**
* 初始化動畫
*/
private void initAnimation() {
upAnimation = new RotateAnimation(0f, -180f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
upAnimation.setDuration(500);
upAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上
downAnimation = new RotateAnimation(-180f, -360f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
downAnimation.setDuration(500);
downAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN :
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE :
int moveY = (int) ev.getY();
// 移動中的y - 按下的y = 間距.
int diff = (moveY - downY) / 2;
// -頭佈局的高度 + 間距 = paddingTop
int paddingTop = -headerViewHeight + diff;
// 如果: -頭佈局的高度 > paddingTop的值 執行super.onTouchEvent(ev);
if (firstVisibleItemPosition == 0
&& -headerViewHeight < paddingTop) {
if (paddingTop > 0 && currentState == DOWN_PULL_REFRESH) { // 完全顯示了.
Log.i(TAG, "鬆開重新整理");
currentState = RELEASE_REFRESH;
refreshHeaderView();
} else if (paddingTop < 0
&& currentState == RELEASE_REFRESH) { // 沒有顯示完全
Log.i(TAG, "下拉重新整理");
currentState = DOWN_PULL_REFRESH;
refreshHeaderView();
}
// 下拉頭佈局
headerView.setPadding(0, paddingTop, 0, 0);
return true;
}
break;
case MotionEvent.ACTION_UP :
// 判斷當前的狀態是鬆開重新整理還是下拉重新整理
if (currentState == RELEASE_REFRESH) {
Log.i(TAG, "重新整理資料.");
// 把頭佈局設定為完全顯示狀態
headerView.setPadding(0, 0, 0, 0);
// 進入到正在重新整理中狀態
currentState = REFRESHING;
refreshHeaderView();
if (mOnRefershListener != null) {
mOnRefershListener.onDownPullRefresh(); // 呼叫使用者的監聽方法
}
} else if (currentState == DOWN_PULL_REFRESH) {
// 隱藏頭佈局
headerView.setPadding(0, -headerViewHeight, 0, 0);
}
break;
default :
break;
}
return super.onTouchEvent(ev);
}
/**
* 根據currentState重新整理頭佈局的狀態
*/
private void refreshHeaderView() {
switch (currentState) {
case DOWN_PULL_REFRESH : // 下拉重新整理狀態
tvState.setText("下拉重新整理");
ivArrow.startAnimation(downAnimation); // 執行向下旋轉
break;
case RELEASE_REFRESH : // 鬆開重新整理狀態
tvState.setText("鬆開重新整理");
ivArrow.startAnimation(upAnimation); // 執行向上旋轉
break;
case REFRESHING : // 正在重新整理中狀態
ivArrow.clearAnimation();
ivArrow.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
tvState.setText("正在重新整理中...");
break;
default :
break;
}
}
/**
* 當滾動狀態改變時回撥
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
// 判斷當前是否已經到了底部
if (isScrollToBottom && !isLoadingMore) {
isLoadingMore = true;