(1)向上滑动 ListView,当最后一个条目滚入屏幕时开始加载更多条目,在列表底部增长一个 footerView:一个 infinite progressBar,一个 textView 显示 “Loading...”;
(2)根据数据加载的结果更新 view:
(2.1)若是已经没有更多条目,则更新 footerView:仅包含一个 textView 显示“No More”;
(2.2)若是成功获取更多条目,则更新 ListView,同时移除(隐藏) footerView;
(2.3)若是加载失败(网络异常等缘由),移除(隐藏) footerView。html
综上述,须要有一个 footerView,它包含两种状态:java
------------------------------- | @ Loading... | (借用 @ 当作infinite progressBar) ------------------------------- ------------------------------- | No More | -------------------------------
这是一个挺简单 UI 需求,比常见的实现方式少了一种状态:android
------------------------------- | 查看更多 | -------------------------------
在这种状态下,点击 footerView 也能够和『上拉』同样加载更多条目。我对比了手Q和微信,手Q就多了这个『查看更多』的状态(固然,必须在上拉时刚好让它停在最后一个条目,否则上拉过头后,就马上变成『Loading...』)。
本需求并不须要这个状态,因此下面的实现分析不会考虑它,因此总体实现相对简单。git
为了实现上述需求,须要考虑三个问题:github
如何定义 footerView?微信
什么时候加载更多?网络
数据加载完毕后,如何更新视图?ide
如上述,footerView 包含两种状态:加载中、没有加载。this
『加载中』包含两个控件,infinite progressBar 和 textView,放进一个 LinearLayout;『没有加载』只包含一个控件,textView,也把它放进一个 LinearLayout;而后把这两个 LinearLayout 放到一个 FrameLayout 内。根据状态决定显示哪一个 LinearLayout。所以只须要一个 public method:spa
public class PullUpLoadListViewFooter extends LinearLayout { public enum State { LOADING, NOT_LOADING, } public void updateView(State state, String content) {} }
向上滑动 ListView,当最后一个条目滚入屏幕时开始加载更多条目。ListView 能够监听滚动事件,所以知道什么时候加载更多。但数据加载的工做显然应该交给控制器,也就是 ListView 的托管者好比 Activity 来完成。
因此,在 ListView 中定义一个接口,并在 ListView 滚动事件中回调这个接口方法:
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;设置标志位表示『已经处于上拉加载状态中』防止重复加载;回调。
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 实现该接口完成加载工做:
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); } } });
ListView 提供一个public方法,根据数据加载的结果更新视图:
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 完成加载数据后,调用 ListView 提供的方法,并更新 adapter 数据集:
listView.onPullUpLoadFinished(false); // Add more data to adapter and notify data set changed to update listView. adapter.addMoreItems(newItems);
上述实现基于 nicolasjafelle/PagingListView,对 PagingListView.java 作了两处较大改动:
(1)数据加载完成后,由PagingListView负责更新adapter,考虑到ListView可能并不清楚adapter的接口,因此仍是交给activity比较好;
// PagingListView的实现 public void onFinishLoading(boolean hasMoreItems, List<? extends Object> { ... ((PagingBaseAdapter) adapter).addMoreItems(newItems); }
(2)PagingListView维护了一个私有成员boolean hasMoreItems
,而后在滚动事件回调onScroll(...)
中,若是该值为false,就不会加载更多数据。
我以为不该该由ListView来维护『是否具备更多的item』,这样会带来一些困惑和额外的工做。好比该值为false的状况下,当外部清空list item后,必须重置 hasMoreItems
,不然没法继续加载。
这样逻辑显得比较乱,而『是否能够加载更多』,应该分红两部分:
由 ListView 判断『没有处于加载状态』而且『已经滚到了最后一个条目』则容许加载;
由 Activity 判断『还有更多的数据』则容许加载。
这样就显得清晰不少了。
你能够从这里获取源码:Learning_Android_Open_Source/Pull_Up_Load_ListView_Sample
以下的GIF演示了上拉加载的过程:
版权声明:《如何实现 Android ListView『上拉加载更多』?》由 WeiYi.Li 在 2016年01月12日写做。著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
文章连接:http://li2.me/2016/01/android-pull-up-lo...