android listview自动加载更多,如何实现 Android ListView『上拉加载更多』?
ListView上拉加載更多的UI需求
(1)向上滑動 ListView,當(dāng)最后一個條目滾入屏幕時開始加載更多條目,在列表底部增加一個 footerView:一個 infinite progressBar,一個 textView 顯示 “Loading...”;
(2)根據(jù)數(shù)據(jù)加載的結(jié)果更新 view:
(2.1)如果已經(jīng)沒有更多條目,則更新 footerView:僅包含一個 textView 顯示“No More”;
(2.2)如果成功獲取更多條目,則更新 ListView,同時移除(隱藏) footerView;
(2.3)如果加載失敗(網(wǎng)絡(luò)異常等原因),移除(隱藏) footerView。
綜上述,需要有一個 footerView,它包含兩種狀態(tài):
-------------------------------
| @ Loading... | (借用 @ 當(dāng)做infinite progressBar)
-------------------------------
-------------------------------
| No More |
-------------------------------
這是一個挺簡單 UI 需求,比常見的實現(xiàn)方式少了一種狀態(tài):
-------------------------------
| 查看更多 |
-------------------------------
在這種狀態(tài)下,點擊 footerView 也可以和『上拉』一樣加載更多條目。我對比了手Q和微信,手Q就多了這個『查看更多』的狀態(tài)(當(dāng)然,必須在上拉時恰好讓它停在最后一個條目,不然上拉過頭后,就立刻變成『Loading...』)。
本需求并不需要這個狀態(tài),所以下面的實現(xiàn)分析不會考慮它,所以整體實現(xiàn)相對簡單。
為了實現(xiàn)上述需求,需要考慮三個問題:
如何定義 footerView?
何時加載更多?
數(shù)據(jù)加載完畢后,如何更新視圖?
如何定義 footerView?
如上述,footerView 包含兩種狀態(tài):加載中、沒有加載。
『加載中』包含兩個控件,infinite progressBar 和 textView,放進一個 LinearLayout;『沒有加載』只包含一個控件,textView,也把它放進一個 LinearLayout;然后把這兩個 LinearLayout 放到一個 FrameLayout 內(nèi)。根據(jù)狀態(tài)決定顯示哪個 LinearLayout。因此只需要一個 public method:
public class PullUpLoadListViewFooter extends LinearLayout {
public enum State {
LOADING,
NOT_LOADING,
}
public void updateView(State state, String content) {}
}
何時加載更多?
向上滑動 ListView,當(dāng)最后一個條目滾入屏幕時開始加載更多條目。ListView 可以監(jiān)聽滾動事件,因此知道何時加載更多。但數(shù)據(jù)加載的工作顯然應(yīng)該交給控制器,也就是 ListView 的托管者比如 Activity 來完成。
所以,在 ListView 中定義一個接口,并在 ListView 滾動事件中回調(diào)這個接口方法:
public class PullUpLoadListView extends ListView {
public interface OnPullUpLoadListener {
void onPullUpLoading();
}
public void setOnPullUpLoadListener(OnPullUpLoadListener listener) {
mOnPullUpLoadListener = listener;
}
private OnPullUpLoadListener mOnPullUpLoadListener;
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// Start a new loading when the last item scrolls into screen, instead of overriding method onTouchEvent.
// 檢查是否到listView底部,檢查callbacks是否注冊:
if (needLoad(...)) {
startPullUpLoad();
}
}
};
}
startPullUpLoad() 是listView 處理上拉加載的核心代碼:秀出顯示『Loading...』的footerView;設(shè)置標(biāo)志位表示『已經(jīng)處于上拉加載狀態(tài)中』防止重復(fù)加載;回調(diào)。
private void startPullUpLoad() {
if (mOnPullUpLoadListener != null) {
// Show the foot view and update its state to LOADING.
showFooterView();
// Set flag
mIsPullUpLoading = true;
// Call the callback to notify the listView's hosted controller to load data.
mOnPullUpLoadListener.onPullUpLoading();
}
}
再由 Activity 實現(xiàn)該接口完成加載工作:
listView.setOnPullUpLoadListener(new PullUpLoadListView.OnPullUpLoadListener() {
@Override
public void onPullUpLoading() {
if (shouldLoadMore) {
// Loading more data
new LoadDataAsyncTask().execute();
} else {
// Already has no more data
// 下面會講到這個方法
listView.onPullUpLoadFinished(true);
}
}
});
數(shù)據(jù)加載完畢后,如何更新視圖?
ListView 提供一個public方法,根據(jù)數(shù)據(jù)加載的結(jié)果更新視圖:
public class PullUpLoadListView extends ListView {
// When loading finished, the controller should call this public method to update footer view.
public void onPullUpLoadFinished(boolean hasNoMoreItems) {
// Clear flag
mIsPullUpLoading = false;
if (hasNoMoreItems) {
// when have no more items, update footer view to: NO MORE
mFooterView.updateView(PullUpLoadListViewFooter.State.NOT_LOADING, FOOTER_VIEW_CONTENT_NO_MORE);
} else {
// The other cases: (1)Loading succeed and still has more items, (2)Loading failed,
// should hide footer view.
hideFooterView();
}
}
}
Activity 完成加載數(shù)據(jù)后,調(diào)用 ListView 提供的方法,并更新 adapter 數(shù)據(jù)集:
listView.onPullUpLoadFinished(false);
// Add more data to adapter and notify data set changed to update listView.
adapter.addMoreItems(newItems);
源碼實現(xiàn)總結(jié)
(1)數(shù)據(jù)加載完成后,由PagingListView負責(zé)更新adapter,考慮到ListView可能并不清楚adapter的接口,所以還是交給activity比較好;
// PagingListView的實現(xiàn)
public void onFinishLoading(boolean hasMoreItems, List extends Object> {
...
((PagingBaseAdapter) adapter).addMoreItems(newItems);
}
(2)PagingListView維護了一個私有成員boolean hasMoreItems,然后在滾動事件回調(diào)onScroll(...)中,如果該值為false,就不會加載更多數(shù)據(jù)。
我覺得不應(yīng)該由ListView來維護『是否具有更多的item』,這樣會帶來一些困惑和額外的工作。比如該值為false的情況下,當(dāng)外部清空list item后,必須重置 hasMoreItems,否則無法繼續(xù)加載。
這樣邏輯顯得比較亂,而『是否可以加載更多』,應(yīng)該分成兩部分:
由 ListView 判斷『沒有處于加載狀態(tài)』并且『已經(jīng)滾到了最后一個條目』則允許加載;
由 Activity 判斷『還有更多的數(shù)據(jù)』則允許加載。
這樣就顯得清晰很多了。
如下的GIF演示了上拉加載的過程:
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的android listview自动加载更多,如何实现 Android ListView『上拉加载更多』?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: scala mysql连接池_Java与
- 下一篇: 后发送过慢的问题_点胶阀使用常见问题怎么