国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現上拉加載更多ListView(PulmListView)

2019-12-12 05:16:24
字體:
來源:轉載
供稿:網友

思路

今天帶大家實現一個上拉加載更多的ListView.GitHub傳送門:PulmListView, 歡迎大家fork&&star.

先帶大家理一下思路, 如果我們要實現一個上拉加載更多的ListView, 我們需要實現的功能包括:
1.一個自定義的ListView, 并且該ListView能夠判斷當前是否已經處于最底部.
 2.一個自定義的FooterView, 用于在ListView加載更多的過程中進行UI展示.
 3.關聯FooterView和ListView, 包括加載時機判斷、FooterView的顯示和隱藏.
 4.提供一個加載更多的接口, 便于回調用戶真正加載更多的功能實現.
 5.提供一個加載更多結束的回調方法, 用于添加用戶的最新數據并更新相關狀態標記和UI顯示. 

針對上面的5個功能, 我們挨個分析對應的實現方法.

功能1(自定義ListView)

我們可以通過繼承ListView, 實現一個自定義的PulmListView.

public class PulmListView extends ListView {  public PulmListView(Context context) {    this(context, null);  }  public PulmListView(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public PulmListView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    // 初始化    init();  }}

只是實現ListView的三個構造函數還不夠, 我們需要ListView能夠判斷當前的ListView是否滑動到最后一個元素.

判斷是否滑動到最后一個元素, 我們可以通過為ListView設置OnScrollListener來實現.代碼如下:

private void init() {  super.setOnScrollListener(new OnScrollListener() {    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {      // 調用用戶設置的OnScrollListener      if (mUserOnScrollListener != null) {        mUserOnScrollListener.onScrollStateChanged(view, scrollState);      }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {      // 調用用戶設置的OnScrollListener      if (mUserOnScrollListener != null) {        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);      }      // firstVisibleItem是當前屏幕能顯示的第一個元素的位置      // visibleItemCount是當前屏幕能顯示的元素的個數      // totalItemCount是ListView包含的元素總數      int lastVisibleItem = firstVisibleItem + visibleItemCount;      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {        if (mOnPullUpLoadMoreListener != null) {          mIsLoading = true;          mOnPullUpLoadMoreListener.onPullUpLoadMore();        }      }    }  });}

從代碼注釋可以知道, 通過(firstVisibleItem + visibleItemCount)可以獲取當前屏幕已經展示的元素個數, 如果已經展示的元素個數等于ListView的元素總數, 則此時可以認為ListView已經滑動到底部.

功能2(自定義的FooterView)

這里我們可以實現一個比較簡單的FooterView, 即加載更多的UI布局.例如我們可以展示一個ProgressBar和一行文字, 具體代碼如下:

/** * 加載更多的View布局,可自定義. */public class LoadMoreView extends LinearLayout {  public LoadMoreView(Context context) {    this(context, null);  }  public LoadMoreView(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    init();  }  private void init() {    LayoutInflater.from(getContext()).inflate(R.layout.lv_load_more, this);  }}

布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:id="@+id/id_load_more_layout"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:orientation="horizontal"  android:gravity="center"  android:layout_margin="@dimen/loading_view_margin_layout">  <ProgressBar    android:id="@+id/id_loading_progressbar"    android:layout_width="@dimen/loading_view_progress_size"    android:layout_height="@dimen/loading_view_progress_size"    android:indeterminate="true"    style="?android:progressBarStyleSmall"/>  <TextView    android:id="@+id/id_loading_label"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/page_loading"/></LinearLayout>

功能3(關聯ListView和FooterView)

第一,我們需要在ListView中通過一個變量保存FooterView, 并且在構造函數中將其實例化.

private View mLoadMoreView;private void init() {  mLoadMoreView = new LoadMoreView(getContext());}

第二,我們需要控制FooterView的顯示和隱藏.考慮一下FooterView的顯示和隱藏的時機:
•顯示的時機: ListView處于最底部并且當前還有更多的數據需要加載.
•隱藏的時機: ListView結束完加載更多的操作. 

為了判斷當前是否還有數據需要加載, 因此我們需要定義一個boolean變量mIsPageFinished, 表示數據加載是否結束.
為了保證同一時間只進行一次數據加載過程, 因此我們還需要定義一個boolean變量mIsLoading, 表示當前是否已經處于數據加載狀態.

明確了FooterView的顯示和隱藏時機, 也有了控制狀態的變量, 代碼也就比較容易實現了.

顯示時機:

private void init() {  mIsLoading = false; // 初始化時沒處于加載狀態  mIsPageFinished = false; // 初始化時默認還有更多數據需要加載  mLoadMoreView = new LoadMoreView(getContext()); // 實例化FooterView  super.setOnScrollListener(new OnScrollListener() {    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {      // 調用用戶設置的OnScrollListener      if (mUserOnScrollListener != null) {        mUserOnScrollListener.onScrollStateChanged(view, scrollState);      }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {      // 調用用戶設置的OnScrollListener      if (mUserOnScrollListener != null) {        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);      }      int lastVisibleItem = firstVisibleItem + visibleItemCount;      // 當處于ListView尾部且有更多數據需要加載且當前沒有加載程序再進行中時, 執行加載更多操作      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {        if (mOnPullUpLoadMoreListener != null) {          mIsLoading = true; // 將加載更多進行時狀態設置為true          showLoadMoreView(); // 顯示加載更多布局          mOnPullUpLoadMoreListener.onPullUpLoadMore(); // 調用用戶設置的加載更多回調接口        }      }    }  });}private void showLoadMoreView() {  // 這里將加載更多的根布局id設置為id_load_more_layout, 便于用戶自定制加載更多布局.  if (findViewById(R.id.id_load_more_layout) == null) {    addFooterView(mLoadMoreView);  }}

隱藏時機:

/** * 加載更多結束后ListView回調方法. * * @param isPageFinished 分頁是否結束 * @param newItems    分頁加載的數據 * @param isFirstLoad  是否第一次加載數據(用于配置下拉刷新框架使用, 避免出現頁面閃現) */public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {  mIsLoading = false; // 標記當前已經沒有加載更多的程序在執行  setIsPageFinished(isPageFinished); // 設置分頁是否結束標志并移除FooterView}private void setIsPageFinished(boolean isPageFinished) {  mIsPageFinished = isPageFinished;  removeFooterView(mLoadMoreView);}

功能4(上拉加載更多實現的回調接口)

這個比較簡單, 我們定義一個interface, 便于回調用戶真正的加載更多的實現方法.

/** * 上拉加載更多的回調接口 */public interface OnPullUpLoadMoreListener {  void onPullUpLoadMore();}private OnPullUpLoadMoreListener mOnPullUpLoadMoreListener;/** * 設置上拉加載更多的回調接口. * @param l 上拉加載更多的回調接口 */public void setOnPullUpLoadMoreListener(OnPullUpLoadMoreListener l) {  this.mOnPullUpLoadMoreListener = l;}

功能5(加載更多的結束回調)

為了在PulmListView中維護數據集合, 必須自定義一個Adapter, 在Adapter中使用List存儲數據集合, 并提交增刪的方法.

自定義的Adapter:

/** * 抽象的Adapter. */public abstract class PulmBaseAdapter<T> extends BaseAdapter {  protected List<T> items;  public PulmBaseAdapter() {    this.items = new ArrayList<>();  }  public PulmBaseAdapter(List<T> items) {    this.items = items;  }  public void addMoreItems(List<T> newItems, boolean isFirstLoad) {    if (isFirstLoad) {      this.items.clear();    }    this.items.addAll(newItems);    notifyDataSetChanged();  }  public void removeAllItems() {    this.items.clear();    notifyDataSetChanged();  }}

為什么在addMoreItems方法中要增加一個isFirstLoad變量呢?

是因為上拉加載更多通常要配合下拉刷新使用.而下拉刷新的過程中會牽扯到ListView的數據集合clear然后再addAll.如果沒有isFirstLoad參數, 那用戶下拉刷新去更新ListView的數據集合就必須分為兩步:
1.removeAllItems并進行notifyDataSetChanged.
 2.addMoreItems并進行notifyDataSetChanged. 

同一時間連續兩次notifyDataSetChanged會導致屏幕閃屏, 因此這里提交了一個isFirstLoad方法.當是第一次加載數據時, 會先clear掉所有的數據, 然后再addAll, 最后再notify.

有了自定義的adapter, 就可以寫加載更多結束的回調函數了:

/** * 加載更多結束后ListView回調方法. * * @param isPageFinished 分頁是否結束 * @param newItems    分頁加載的數據 * @param isFirstLoad  是否第一次加載數據(用于配置下拉刷新框架使用, 避免出現頁面閃現) */public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {  mIsLoading = false;  setIsPageFinished(isPageFinished);  // 添加更新后的數據  if (newItems != null && newItems.size() > 0) {    PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();    adapter.addMoreItems(newItems, isFirstLoad);  }}

這里需要注意, 當添加了FooterView或者HeaderView之后, 我們無法通過listview.getAdapter拿到我們自定義的adapter, 必須按照如下步驟:

復制代碼 代碼如下:
PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();

參考
 1.PagingListView

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大悟县| 大连市| 罗平县| 七台河市| 鱼台县| 怀集县| 涟水县| 安康市| 容城县| 池州市| 分宜县| 威信县| 青海省| 琼中| 定襄县| 台山市| 湟源县| 黄梅县| 屏南县| 鄂托克前旗| 永州市| 卫辉市| 观塘区| 周宁县| 新宁县| 龙江县| 广水市| 泰宁县| 泸溪县| 乐业县| 昌乐县| 光泽县| 阿坝| 南部县| 南川市| 穆棱市| 清流县| 启东市| 黄梅县| 黄梅县| 兰西县|