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

思路

今天带大家实现一个上拉加载更多的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

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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索上拉加载ListView
listview实现上拉加载、listview实现分页加载、listview分页加载、listview上拉加载、listview异步加载图片,以便于您获取更多的相关知识。

时间: 2024-09-29 16:19:23

Android实现上拉加载更多ListView(PulmListView)_Android的相关文章

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

思路 今天带大家实现一个上拉加载更多的ListView.GitHub传送门:PulmListView, 欢迎大家fork&&star. 先带大家理一下思路, 如果我们要实现一个上拉加载更多的ListView, 我们需要实现的功能包括: 1.一个自定义的ListView, 并且该ListView能够判断当前是否已经处于最底部.  2.一个自定义的FooterView, 用于在ListView加载更多的过程中进行UI展示.  3.关联FooterView和ListView, 包括加载时机判断.

Android实现上拉加载更多以及下拉刷新功能(ListView)_Android

首先为大家介绍Andorid5.0原生下拉刷新简单实现. 先上效果图: 相对于上一个19.1.0版本中的横条效果好看了很多.使用起来也很简单. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" and

Android实现上拉加载更多以及下拉刷新功能(ListView)

首先为大家介绍Andorid5.0原生下拉刷新简单实现. 先上效果图: 相对于上一个19.1.0版本中的横条效果好看了很多.使用起来也很简单. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" and

Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法_Android

RecyclerView 已经出来很久了,但是在项目中之前都使用的是ListView,最近新的项目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,网上吧啦吧啦没有合适的自己总结了一哈. 先贴图上来看看:     使用RecyclerView实现上拉加载更多和下拉刷新的功能我自己有两种方式: 1.使用系统自带的Android.support.v4.widget.SwipeRefreshLayout这个控价来实现. 2.自定义的里面带有RecyleView的控件. 使用Recycl

Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法

RecyclerView 已经出来很久了,但是在项目中之前都使用的是ListView,最近新的项目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,网上吧啦吧啦没有合适的自己总结了一哈. 先贴图上来看看: 使用RecyclerView实现上拉加载更多和下拉刷新的功能我自己有两种方式: 1.使用系统自带的Android.support.v4.widget.SwipeRefreshLayout这个控价来实现. 2.自定义的里面带有RecyleView的控件. 使用RecycleVie

Android RecyclerView上拉加载更多功能回弹实现代码

实现原理是使用RecyclerView的OnTouchListener方法监听滑动 在adapter里面增加两项footview 其中date.size为显示的加载条,可以自定义,date.size+1为空白的View,我们设置其高度为0 我们通过LinearLayoutManager的 findLastVisibleItemPosition判断显示的最后一条数据,如果是空白view,表示加载条已经完全展示,松开即可刷新. 回弹效果是通过在滑动时动态改变空白view的高度,达到阻尼效果 ,回弹时

GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能(推荐)_Android

原理和listview一样 ,都是重写Android原生控件 Activity package com.example.refreshgridview; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.widget.GridView; import android.widget.Toast; import

安卓 scrollview嵌套listview上拉加载更多怎么实现啊

问题描述 安卓 scrollview嵌套listview上拉加载更多怎么实现啊 5C 如题 这个怎么实现啊,嵌套了监听不到 lv.setOnScrollListener(this) 这个事件 解决方案 Android scrollview中嵌套listview实现listview的下拉刷新上拉加载更多Android开发--上拉加载更多ListView实现ListView实现上拉加载更多 解决方案二: scrollview 直接嵌套listview 是不会实现上拉加载.两者一起使用起了冲突.这个时

Android Recyclerview实现上拉加载更多功能

在项目中使用列表的下拉刷新和上拉加载更多是很常见的功能,下拉刷新我们可以用Android自带的SwipeRefreshLayout这个很好解决.但是上拉加载更多就要去找一些框架了,刚开始的时候我找到一个Mugen的github开源框架,但是有个问题,当页面能够一次加载全部item的时候,上拉加载的功能就失效了. 这是因为当界面一次能够加载完全部item的时候,继续往上拉,Recyclerview的滑动监听,中的onScrolled方法只会在页面加载的时候调用一次,只后就不会被调用了,并且dy=0