欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)上拉加載更多ListView(PulmListView)

 更新時(shí)間:2016年09月15日 09:03:14   作者:zinss26914  
這篇文章主要介紹了Android實(shí)現(xiàn)上拉加載更多ListView:PulmListView,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

思路

今天帶大家實(shí)現(xiàn)一個(gè)上拉加載更多的ListView.GitHub傳送門:PulmListView, 歡迎大家fork&&star.

先帶大家理一下思路, 如果我們要實(shí)現(xiàn)一個(gè)上拉加載更多的ListView, 我們需要實(shí)現(xiàn)的功能包括:
1.一個(gè)自定義的ListView, 并且該ListView能夠判斷當(dāng)前是否已經(jīng)處于最底部.
 2.一個(gè)自定義的FooterView, 用于在ListView加載更多的過程中進(jìn)行UI展示.
 3.關(guān)聯(lián)FooterView和ListView, 包括加載時(shí)機(jī)判斷、FooterView的顯示和隱藏.
 4.提供一個(gè)加載更多的接口, 便于回調(diào)用戶真正加載更多的功能實(shí)現(xiàn).
 5.提供一個(gè)加載更多結(jié)束的回調(diào)方法, 用于添加用戶的最新數(shù)據(jù)并更新相關(guān)狀態(tài)標(biāo)記和UI顯示. 

針對(duì)上面的5個(gè)功能, 我們挨個(gè)分析對(duì)應(yīng)的實(shí)現(xiàn)方法.

功能1(自定義ListView)

我們可以通過繼承ListView, 實(shí)現(xiàn)一個(gè)自定義的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();
  }
}

只是實(shí)現(xiàn)ListView的三個(gè)構(gòu)造函數(shù)還不夠, 我們需要ListView能夠判斷當(dāng)前的ListView是否滑動(dòng)到最后一個(gè)元素.

判斷是否滑動(dòng)到最后一個(gè)元素, 我們可以通過為L(zhǎng)istView設(shè)置OnScrollListener來實(shí)現(xiàn).代碼如下:

private void init() {
  super.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // 調(diào)用用戶設(shè)置的OnScrollListener
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScrollStateChanged(view, scrollState);
      }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // 調(diào)用用戶設(shè)置的OnScrollListener
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
      }

      // firstVisibleItem是當(dāng)前屏幕能顯示的第一個(gè)元素的位置
      // visibleItemCount是當(dāng)前屏幕能顯示的元素的個(gè)數(shù)
      // totalItemCount是ListView包含的元素總數(shù)
      int lastVisibleItem = firstVisibleItem + visibleItemCount;
      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
        if (mOnPullUpLoadMoreListener != null) {
          mIsLoading = true;
          mOnPullUpLoadMoreListener.onPullUpLoadMore();
        }
      }
    }
  });
}

從代碼注釋可以知道, 通過(firstVisibleItem + visibleItemCount)可以獲取當(dāng)前屏幕已經(jīng)展示的元素個(gè)數(shù), 如果已經(jīng)展示的元素個(gè)數(shù)等于ListView的元素總數(shù), 則此時(shí)可以認(rèn)為L(zhǎng)istView已經(jīng)滑動(dòng)到底部.

功能2(自定義的FooterView)

這里我們可以實(shí)現(xiàn)一個(gè)比較簡(jiǎn)單的FooterView, 即加載更多的UI布局.例如我們可以展示一個(gè)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(關(guān)聯(lián)ListView和FooterView)

第一,我們需要在ListView中通過一個(gè)變量保存FooterView, 并且在構(gòu)造函數(shù)中將其實(shí)例化.

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

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

為了判斷當(dāng)前是否還有數(shù)據(jù)需要加載, 因此我們需要定義一個(gè)boolean變量mIsPageFinished, 表示數(shù)據(jù)加載是否結(jié)束.
為了保證同一時(shí)間只進(jìn)行一次數(shù)據(jù)加載過程, 因此我們還需要定義一個(gè)boolean變量mIsLoading, 表示當(dāng)前是否已經(jīng)處于數(shù)據(jù)加載狀態(tài).

明確了FooterView的顯示和隱藏時(shí)機(jī), 也有了控制狀態(tài)的變量, 代碼也就比較容易實(shí)現(xiàn)了.

顯示時(shí)機(jī):

private void init() {
  mIsLoading = false; // 初始化時(shí)沒處于加載狀態(tài)
  mIsPageFinished = false; // 初始化時(shí)默認(rèn)還有更多數(shù)據(jù)需要加載
  mLoadMoreView = new LoadMoreView(getContext()); // 實(shí)例化FooterView
  super.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // 調(diào)用用戶設(shè)置的OnScrollListener
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScrollStateChanged(view, scrollState);
      }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // 調(diào)用用戶設(shè)置的OnScrollListener
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
      }

      int lastVisibleItem = firstVisibleItem + visibleItemCount;
      // 當(dāng)處于ListView尾部且有更多數(shù)據(jù)需要加載且當(dāng)前沒有加載程序再進(jìn)行中時(shí), 執(zhí)行加載更多操作
      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
        if (mOnPullUpLoadMoreListener != null) {
          mIsLoading = true; // 將加載更多進(jìn)行時(shí)狀態(tài)設(shè)置為true
          showLoadMoreView(); // 顯示加載更多布局
          mOnPullUpLoadMoreListener.onPullUpLoadMore(); // 調(diào)用用戶設(shè)置的加載更多回調(diào)接口
        }
      }
    }
  });
}

private void showLoadMoreView() {
  // 這里將加載更多的根布局id設(shè)置為id_load_more_layout, 便于用戶自定制加載更多布局.
  if (findViewById(R.id.id_load_more_layout) == null) {
    addFooterView(mLoadMoreView);
  }
}

隱藏時(shí)機(jī):

/**
 * 加載更多結(jié)束后ListView回調(diào)方法.
 *
 * @param isPageFinished 分頁(yè)是否結(jié)束
 * @param newItems    分頁(yè)加載的數(shù)據(jù)
 * @param isFirstLoad  是否第一次加載數(shù)據(jù)(用于配置下拉刷新框架使用, 避免出現(xiàn)頁(yè)面閃現(xiàn))
 */
public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {
  mIsLoading = false; // 標(biāo)記當(dāng)前已經(jīng)沒有加載更多的程序在執(zhí)行
  setIsPageFinished(isPageFinished); // 設(shè)置分頁(yè)是否結(jié)束標(biāo)志并移除FooterView
}

private void setIsPageFinished(boolean isPageFinished) {
  mIsPageFinished = isPageFinished;
  removeFooterView(mLoadMoreView);
}

功能4(上拉加載更多實(shí)現(xiàn)的回調(diào)接口)

這個(gè)比較簡(jiǎn)單, 我們定義一個(gè)interface, 便于回調(diào)用戶真正的加載更多的實(shí)現(xiàn)方法.

/**
 * 上拉加載更多的回調(diào)接口
 */
public interface OnPullUpLoadMoreListener {
  void onPullUpLoadMore();
}

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

功能5(加載更多的結(jié)束回調(diào))

為了在PulmListView中維護(hù)數(shù)據(jù)集合, 必須自定義一個(gè)Adapter, 在Adapter中使用List存儲(chǔ)數(shù)據(jù)集合, 并提交增刪的方法.

自定義的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方法中要增加一個(gè)isFirstLoad變量呢?

是因?yàn)樯侠虞d更多通常要配合下拉刷新使用.而下拉刷新的過程中會(huì)牽扯到ListView的數(shù)據(jù)集合clear然后再addAll.如果沒有isFirstLoad參數(shù), 那用戶下拉刷新去更新ListView的數(shù)據(jù)集合就必須分為兩步:
1.removeAllItems并進(jìn)行notifyDataSetChanged.
 2.addMoreItems并進(jìn)行notifyDataSetChanged. 

同一時(shí)間連續(xù)兩次notifyDataSetChanged會(huì)導(dǎo)致屏幕閃屏, 因此這里提交了一個(gè)isFirstLoad方法.當(dāng)是第一次加載數(shù)據(jù)時(shí), 會(huì)先clear掉所有的數(shù)據(jù), 然后再addAll, 最后再notify.

有了自定義的adapter, 就可以寫加載更多結(jié)束的回調(diào)函數(shù)了:

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

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

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

參考
 1.PagingListView

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android自定義酒店日期選擇器

    Android自定義酒店日期選擇器

    這篇文章主要為大家詳細(xì)介紹了Android自定義酒店日期選擇器、旅游日期區(qū)間選擇器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Android 使用RecycleView列表實(shí)現(xiàn)加載更多的示例代碼

    Android 使用RecycleView列表實(shí)現(xiàn)加載更多的示例代碼

    這篇文章主要介紹了Android 使用RecycleView列表實(shí)現(xiàn)加載更多的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • kotlin中EditText賦值Type mismatch方式

    kotlin中EditText賦值Type mismatch方式

    這篇文章主要介紹了kotlin中EditText賦值Type mismatch方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • flutter實(shí)現(xiàn)底部導(dǎo)航欄切換

    flutter實(shí)現(xiàn)底部導(dǎo)航欄切換

    這篇文章主要為大家詳細(xì)介紹了flutter實(shí)現(xiàn)底部導(dǎo)航欄切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Kotlin使用滾動(dòng)控件RecyclerView實(shí)例教程

    Kotlin使用滾動(dòng)控件RecyclerView實(shí)例教程

    RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動(dòng),也可以實(shí)現(xiàn)橫向滾動(dòng)(ListView做不到橫向滾動(dòng))。接下來講解RecyclerView的用法
    2022-12-12
  • RecyclerView使用payload實(shí)現(xiàn)局部刷新

    RecyclerView使用payload實(shí)現(xiàn)局部刷新

    這篇文章主要為大家詳細(xì)介紹了RecyclerView使用payload實(shí)現(xiàn)局部刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Android 圖片選擇詳解及實(shí)例代碼

    Android 圖片選擇詳解及實(shí)例代碼

    這篇文章主要介紹了 Android 圖片選擇詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Android應(yīng)用程序“R文件”消失

    Android應(yīng)用程序“R文件”消失

    這篇文章主要介紹了Android應(yīng)用程序“R文件”消失的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • Android自定義進(jìn)度條效果

    Android自定義進(jìn)度條效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義進(jìn)度條效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Android?音頻波形圖實(shí)現(xiàn)效果示例

    Android?音頻波形圖實(shí)現(xiàn)效果示例

    這篇文章主要為大家介紹了Android?音頻波形圖實(shí)現(xiàn)效果示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論