Android 上拉加载更多功能
前几天看了github上面的例子,参照它的实现,自己又稍微改了一点,往项目里面增加了一个上拉加载更多功能。具体的实现如下:
首先要重写ListView:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.AbsListView;
- import android.widget.HeaderViewListAdapter;
- import android.widget.ListAdapter;
- import android.widget.ListView;
- import java.util.List;
- import njucm.edu.loadmore.activities.LoadingView;
- import njucm.edu.loadmore.adapters.PagingBaseAdapter;
- /**
- * Created by Mesogene on 10/9/15.
- */
- public class LoadListView extends ListView {
- private OnScrollListener onScrollListener = null;
- private PageEnableListener pageEnableListener = null;
- LoadingView loadListView = null;
- private boolean isLoading;
- private boolean hasMoreItem;
- private int lastVisibleItem; //最后一个可见的项
- private int totalItemCount; //总的项数
- public LoadListView(Context context) {
- super(context);
- init();
- }
- public LoadListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
- public void setPageEnableListener(PageEnableListener pageEnableListener) {
- this.pageEnableListener = pageEnableListener;
- }
- public boolean isLoading() {
- return isLoading;
- }
- public void setIsLoading(boolean isLoading) {
- this.isLoading = isLoading;
- }
- public boolean isHasMoreItem() {
- return hasMoreItem;
- }
- public void setHasMoreItem(boolean hasMoreItem) {
- this.hasMoreItem = hasMoreItem;
- if(!this.hasMoreItem){ //如果没有更多项,移除底部
- removeFooterView(loadListView);
- }
- else if(findViewById(R.id.loading_view) == null){
- addFooterView(loadListView);
- ListAdapter adapter = ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();
- setAdapter(adapter);
- }
- }
- /**
- * 在下载任务完成之后去调用这个方法
- * @param hasMoreItem 是否还有更多项
- * @param newItems 新的项
- */
- public void onFinsihLoading(boolean hasMoreItem, List<? extends Object> newItems){
- setHasMoreItem(hasMoreItem);
- setIsLoading(false); //下载任务完成后,把loading设置成false
- if(newItems != null && newItems.size() >0){
- ListAdapter adapter = ((HeaderViewListAdapter)getAdapter()).getWrappedAdapter(); //获取这个listview的adapter
- if(adapter instanceof PagingBaseAdapter){
- ((PagingBaseAdapter) adapter).addMoreItems(newItems); //添加项目,包含notify方法
- }
- }
- }
- /**
- * 初始化listview的操作
- */
- private void init(){
- isLoading = false;
- loadListView = new LoadingView(getContext());
- addFooterView(loadListView);
- super.setOnScrollListener(new OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView absListView, int scrollState) {
- if(onScrollListener != null){
- onScrollListener.onScrollStateChanged(absListView, scrollState);
- }
- /**
- * 当你的listview移动到底部的时候,即你看到的最后一项等于总的项数,已经停止滚动 没有正在加载并且还有更多项
- * 的时候会被执行
- */
- if(lastVisibleItem == totalItemCount && scrollState == SCROLL_STATE_IDLE && !isLoading && hasMoreItem){
- if(pageEnableListener != null){
- isLoading = true; //执行之后的状态就是loading
- pageEnableListener.onLoadMoreItems(); //调用回调方法
- }
- }
- }
- @Override
- public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totleItem) {
- //Dispatch to child OnScrollListener
- if (onScrollListener != null) {
- onScrollListener.onScroll(absListView, firstVisibleItem, visibleItemCount, totleItem);
- }
- lastVisibleItem = firstVisibleItem + visibleItemCount; //最后看到的一项
- totalItemCount = totleItem; //总的项数
- }
- });
- }
- @Override
- public void setOnScrollListener(OnScrollListener onScrollListener) {
- this.onScrollListener = onScrollListener;
- }
- public interface PageEnableListener{
- public void onLoadMoreItems();
- }
- }
我们可以看到还要加一个loadingview的,就是你的正在加载界面,这个界面会被动态添加到你的footview里面的:
- package njucm.edu.loadmore.activities;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.LinearLayout;
- import njucm.edu.loadmore.R;
- /**
- * Created by Mesogene on 10/10/15.
- */
- public class LoadingView extends LinearLayout {
- public LoadingView(Context context) {
- super(context);
- init();
- }
- public LoadingView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
- public void init(){
- inflate(getContext(), R.layout.loadinflinear, this);
- }
- }
只是简单重写了一下LinearLayout, 下面只要写一个loading的不局文件就行了
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal" android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_margin="@dimen/dp_10"
- android:id="@+id/loading_view">
- <ProgressBar
- android:id="@+id/video_item_image"
- style="?android:progressBarStyle"
- android:layout_width="@dimen/loading_view_progress_size"
- android:layout_height="@dimen/loading_view_progress_size"
- android:layout_marginRight="@dimen/loading_view_margin_right"
- android:indeterminate="true"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/loading"
- android:layout_gravity="center"
- android:textColor="@color/material_blue_grey_800"
- android:textSize="@dimen/sp_18"/>
- </LinearLayout>
这样基本就已经好了,那么还有一个listview的父类的适配器要自己写一下:
- import android.widget.BaseAdapter;
- import android.widget.ListAdapter;
- import java.util.ArrayList;
- import java.util.List;
- import njucm.edu.loadmore.LoadListView;
- /**
- * Created by Mesogene on 10/12/15.
- */
- public abstract class PagingBaseAdapter<T> extends BaseAdapter {
- protected List<T> items = null;
- public PagingBaseAdapter(List<T> items) {
- this.items = items;
- }
- public PagingBaseAdapter(){
- this.items = new ArrayList<>();
- }
- public void addMoreItems(List<T> items){
- this.items.addAll(items); //把新的项添加到listview里面
- notifyDataSetChanged(); //更新布局
- }
- }
这样之后,你自己的listviewAdapter就可以继承这个类,你的adapter拥有绘制每一个listitem的功能和添加下一页数据项的功能。
- package njucm.edu.loadmore.adapters;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.TextView;
- import java.util.List;
- /**
- * Created by Mesogene on 10/12/15.
- */
- public class MyListAdapter extends PagingBaseAdapter<String> {
- @Override
- public int getCount() {
- return items.size();
- }
- @Override
- public String getItem(int position) {
- return items.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View view, ViewGroup viewGroup) {
- TextView textView;
- String text = getItem(position);
- if(view != null){
- textView = (TextView) view;
- }else {
- textView = (TextView) LayoutInflater.from(viewGroup.getContext()).inflate(android.R.layout.simple_list_item_1, null);
- }
- textView.setText(text);
- return textView;
- }
- }
最后就是如何使用了,再onCreate() 或者 onCreateView() 添加如下代码,我们发现它有一个异步加载的过程,使用到了线程
- li.setAdapter(adapter);
- li.setHasMoreItem(true);
- li.setPageEnableListener(new LoadListView.PageEnableListener() {
- @Override
- public void onLoadMoreItems() {
- if(pager < 3){
- new CountryAsyncTask().execute();
- }else{
- li.onFinsihLoading(false, null);
- }
- }
- });
- private class CountryAsyncTask extends SafeAsyncTask<List<String>>{
- @Override
- public List<String> call() throws Exception { //模拟后台下载数据
- List result = null;
- switch (pager){
- case 0:
- result = firstList;
- break;
- case 1:
- result = secondList;
- break;
- case 2:
- result = thirdList;
- break;
- }
- Thread.sleep(3000);
- return result;
- }
- @Override
- protected void onSuccess(List<String> strings) throws Exception {
- super.onSuccess(strings);
- pager++;
- li.onFinsihLoading(true, strings); //下载成功之后调用的方法,更新UI
- }
- }
这里面可能要自己添加一些数据在firstlist等里面。 还有下面是这个类似于AsyncTask但又不是的,这个类的代码如下
- package njucm.edu.loadmore.activities;
- import android.os.Handler;
- import android.os.Looper;
- import android.util.Log;
- import java.io.InterruptedIOException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.concurrent.Callable;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.Executor;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- /**
- * A class similar but unrelated to android's {@link android.os.AsyncTask}.
- * <p/>
- * Unlike AsyncTask, this class properly propagates exceptions.
- * <p/>
- * If you're familiar with AsyncTask and are looking for {@link android.os.AsyncTask#doInBackground(Object[])},
- * we've named it {@link #call()} here to conform with java 1.5's {@link java.util.concurrent.Callable} interface.
- * <p/>
- * Current limitations: does not yet handle progress, although it shouldn't be
- * hard to add.
- * <p/>
- * If using your own executor, you must call future() to get a runnable you can execute.
- *
- * @param <ResultT>
- */
- public abstract class SafeAsyncTask<ResultT> implements Callable<ResultT> { //Callable可以返回任意类型。1.5 以后加入
- public static final int DEFAULT_POOL_SIZE = 25; //默认的线程池的大小是25
- protected static final Executor DEFAULT_EXECUTOR = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE); //利用线程池
- protected Handler handler;
- protected Executor executor;
- protected StackTraceElement[] launchLocation;
- protected FutureTask<Void> future;
- /**
- * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE) and
- * Handler to new Handler()
- */
- public SafeAsyncTask() {
- this.executor = DEFAULT_EXECUTOR;
- }
- /**
- * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE)
- */
- public SafeAsyncTask(Handler handler) {
- this.handler = handler;
- this.executor = DEFAULT_EXECUTOR; //线程池用默认的设置
- }
- /**
- * Sets Handler to new Handler()
- */
- public SafeAsyncTask(Executor executor) {
- this.executor = executor;
- }
- public SafeAsyncTask(Handler handler, Executor executor) {
- this.handler = handler;
- this.executor = executor;
- }
- public FutureTask<Void> future() {
- future = new FutureTask<Void>(newTask());
- return future;
- }
- public SafeAsyncTask<ResultT> executor(Executor executor) {
- this.executor = executor;
- return this;
- }
- public Executor executor() {
- return executor;
- }
- public SafeAsyncTask<ResultT> handler(Handler handler) {
- this.handler = handler;
- return this;
- }
- public Handler handler() {
- return handler;
- }
- public void execute() {
- execute(Thread.currentThread().getStackTrace());
- }
- protected void execute(StackTraceElement[] launchLocation) {
- this.launchLocation = launchLocation;
- executor.execute(future());
- }
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (future == null) throw new UnsupportedOperationException("You cannot cancel this task before calling future()");
- return future.cancel(mayInterruptIfRunning);
- }
- /**
- * @throws Exception, captured on passed to onException() if present.
- */
- protected void onPreExecute() throws Exception {
- }
- /**
- * @param t the result of {@link #call()}
- * @throws Exception, captured on passed to onException() if present.
- */
- @SuppressWarnings({"UnusedDeclaration"})
- protected void onSuccess(ResultT t) throws Exception {
- }
- /**
- * Called when the thread has been interrupted, likely because
- * the task was canceled.
- * <p/>
- * By default, calls {@link #onException(Exception)}, but this method
- * may be overridden to handle interruptions differently than other
- * exceptions.
- *
- * @param e an InterruptedException or InterruptedIOException
- */
- protected void onInterrupted(Exception e) {
- onException(e);
- }
- /**
- * Logs the exception as an Error by default, but this method may
- * be overridden by subclasses.
- *
- * @param e the exception thrown from {@link #onPreExecute()}, {@link #call()}, or {@link #onSuccess(Object)}
- * @throws RuntimeException, ignored
- */
- protected void onException(Exception e) throws RuntimeException {
- onThrowable(e);
- }
- protected void onThrowable(Throwable t) throws RuntimeException {
- Log.e("roboguice", "Throwable caught during background processing", t);
- }
- /**
- * @throws RuntimeException, ignored
- */
- protected void onFinally() throws RuntimeException {
- }
- protected Task<ResultT> newTask() {
- return new Task<ResultT>(this);
- }
- public static class Task<ResultT> implements Callable<Void> {
- protected SafeAsyncTask<ResultT> parent;
- protected Handler handler;
- public Task(SafeAsyncTask<ResultT> parent) {
- this.parent = parent;
- this.handler = parent.handler != null ? parent.handler : new Handler(Looper.getMainLooper());
- }
- public Void call() throws Exception {
- try {
- doPreExecute();
- doSuccess(doCall());
- } catch (final Exception e) {
- try {
- doException(e);
- } catch (Exception f) {
- // logged but ignored
- Log.e("BACKGROUND_TASK", "Exception in", f);
- }
- } catch (final Throwable t) {
- try {
- doThrowable(t);
- } catch (Exception f) {
- // logged but ignored
- Log.e("BACKGROUND_TASK", "Exception in", f);
- }
- } finally {
- doFinally();
- }
- return null;
- }
- protected void doPreExecute() throws Exception {
- postToUiThreadAndWait(new Callable<Object>() {
- public Object call() throws Exception {
- parent.onPreExecute();
- return null;
- }
- });
- }
- protected ResultT doCall() throws Exception {
- return parent.call();
- }
- protected void doSuccess(final ResultT r) throws Exception {
- postToUiThreadAndWait(new Callable<Object>() {
- public Object call() throws Exception {
- parent.onSuccess(r);
- return null;
- }
- });
- }
- protected void doException(final Exception e) throws Exception {
- if (parent.launchLocation != null) {
- final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
- stack.addAll(Arrays.asList(parent.launchLocation));
- e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
- }
- postToUiThreadAndWait(new Callable<Object>() {
- public Object call() throws Exception {
- if (e instanceof InterruptedException || e instanceof InterruptedIOException) parent.onInterrupted(e);
- else parent.onException(e);
- return null;
- }
- });
- }
- protected void doThrowable(final Throwable e) throws Exception {
- if (parent.launchLocation != null) {
- final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
- stack.addAll(Arrays.asList(parent.launchLocation));
- e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
- }
- postToUiThreadAndWait(new Callable<Object>() {
- public Object call() throws Exception {
- parent.onThrowable(e);
- return null;
- }
- });
- }
- protected void doFinally() throws Exception {
- postToUiThreadAndWait(new Callable<Object>() {
- public Object call() throws Exception {
- parent.onFinally();
- return null;
- }
- });
- }
- /**
- * Posts the specified runnable to the UI thread using a handler,
- * and waits for operation to finish. If there's an exception,
- * it captures it and rethrows it.
- *
- * @param c the callable to post
- * @throws Exception on error
- */
- protected void postToUiThreadAndWait(final Callable c) throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final Exception[] exceptions = new Exception[1];
- // Execute onSuccess in the UI thread, but wait
- // for it to complete.
- // If it throws an exception, capture that exception
- // and rethrow it later.
- handler.post(new Runnable() {
- public void run() {
- try {
- c.call();
- } catch (Exception e) {
- exceptions[0] = e;
- } finally {
- latch.countDown();
- }
- }
- });
- // Wait for onSuccess to finish
- latch.await();
- if (exceptions[0] != null) throw exceptions[0];
- }
- }
- }
好了,最简单的上拉加载就是这个样子了。我已经把它集成进了自己的项目里面。
Android 上拉加载更多功能的更多相关文章
- Android 开发 上拉加载更多功能实现
实现思维 开始之前先废话几句,Android系统没有提供上拉加载的控件,只提供了下拉刷新的SwipeRefreshLayout控件.这个控件我们就不废话,无法实现上拉刷新的功能.现在我们说说上拉加载更 ...
- Flutter移动电商实战 --(20)首页上拉加载更多功能的制作
这节课学习一下上拉加载效果,其实现在上拉加载的插件有很多,但是还没有一个插件可以说完全一枝独秀,我也找了一个插件,这个插件的优点就是服务比较好,作者能及时回答大家的问题.我觉的选插件也是选人,人对了, ...
- android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)
Android实现上拉加载更多功能以及下拉刷新功能, 采用了目前比较火的PullToRefresh,他是目前实现比较好的下拉刷新的类库. 目前他支持的控件有:ListView, ExpandableL ...
- Android5.0新特性:RecyclerView实现上拉加载更多
RecyclerView是Android5.0以后推出的新控件,相比于ListView可定制性更大,大有取代ListView之势.下面这篇博客主要来实现RecyclerView的上拉加载更多功能. 基 ...
- SwipeRefreshLayout详解和自定义上拉加载更多
个人主页 演示Demo下载 本文重点介绍了SwipeRefreshLayout的使用和自定View继承SwipeRefreshLayout添加上拉加载更多的功能. 介绍之前,先来看一下SwipeRef ...
- 实现上拉加载更多的SwipeRefreshLayout
转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...
- 自定义ListView下拉刷新上拉加载更多
自定义ListView下拉刷新上拉加载更多 自定义RecyclerView下拉刷新上拉加载更多 Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时 ...
- Android中自定义ListView实现上拉加载更多和下拉刷新
ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能.这里我就简单记录一下实现过程. 实现这个功能的方法不止一个,Gi ...
- android ListView下拉刷新 上拉加载更多
背景 最近在公司的项目中要使用到ListView的下拉刷新和上拉加载更多(貌似现在是个项目就有这个功能!哈哈),其实这个东西GitHub上很多,但是我感觉那些框架太大,而且我这个项目只用到了ListV ...
随机推荐
- 8 Things Every Person Should Do Before 8 A.M.
https://medium.com/@benjaminhardy/8-things-every-person-should-do-before-8-a-m-cc0233e15c8d 1. Get A ...
- 编程概念--使用async和await的异步编程
Asynchronous Programming with Async and Await You can avoid performance bottlenecks and enhance the ...
- chrome插件background.js 和 popup.js 交互
要实现background.js 和 popup.js 之间的交互,首先需要先配置好 manifest.json文件,如: "background":{ //"page& ...
- NOI2002robot
这题又是纯数论题…… 独立数就是欧拉函数,政客和军人的含义已经说的很清楚了,学者是最多的…… 首先,如果我们知道了政客和军人的答案,那就只要用n的所有因子的欧拉函数值减去这两个值,然后取模就行了. 但 ...
- Microsoft强大团队(源代码)管理工具--TFS2010 与vs结合
今天看了与vs 集成原理工具 TFS 2010, 角色分配.项目管理.开发源代码管理.任务分配管理.测试文档管理及跟踪等管理流程.代码版本的分支与合并等等,功能好强大啊. 以下将其安装配置简要介绍(以 ...
- Socket编程(九)
此为网络编程的一个系列,后续会把内容补上.....
- 统一Matlab下不同子图的色标colorbar
Reference:http://www.mathworks.com/matlabcentral/answers/100950-how-can-i-have-a-standard-colorbar-f ...
- 多线程程序设计学习(7)read-write lock pattern
Read-Write Lock Pattern[读写]一:Read-Write Lock Pattern的参与者--->读写锁--->数据(共享资源)--->读线程--->写线 ...
- 软件测试模型汇总-V模型,W模型,X模型,H模型
V模型 在软件测试方面,V模型是最广为人知的模型,尽管很多富有实际经验的测试人员还是不太熟悉V模型,或者其它的模型.V模型已存在了很长时间,和瀑布开发模型有着一些共同的特性,由此也和瀑布模型一样地受到 ...
- 黑盒测试用例设计方法&理论结合实际 -> 判定表驱动法
一. 概念 判定表是分析和表达多逻辑条件下执行不同操作的情况的工具. 二. 判定表驱动法的应用 判定表的优点: a. 能够将复杂的问题按照各种可能的情况全部列举出来,简明并避免遗漏.因此,利用判定表能 ...