Android实现上拉加载更多ListView(PulmListView)

Android实现上拉加载更多ListView(PulmListView),第1张

概述思路今天带大家实现一个上拉加载更多的ListView.GitHub传送门:PulmListView,欢迎大家fork&&star.

思路

今天带大家实现一个上拉加载更多的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,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,0);  }  public LoadMoreVIEw(Context context,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"    />  <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,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  是否第一次加载数据(用于配置下拉刷新框架使用,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,必须按照如下步骤:

复制代码 代码如下:@H_502_140@PulmBaseAdapter adapter = (PulmBaseAdapter) ((headerVIEwlistadapter) getAdapter()).getWrappedAdapter();

参考
 1.PagingListView

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android实现上拉加载更多ListView(PulmListView)全部内容,希望文章能够帮你解决Android实现上拉加载更多ListView(PulmListView)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1148155.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-31
下一篇2022-05-31

发表评论

登录后才能评论

评论列表(0条)

    保存