51dev.com IT技术开发者社区

51dev.com 技术开发者社区

Android中listView的下拉加载功能实现

Android互联网报道阅读(66)2019-06-04 收藏0次评论

今天给大家讲讲android开发中比较常见的listView的下拉加载,其实也可以叫做分页加载。为什么会有这个叫法呢?说说我的理解吧!

从字面上很好理解。当你滑动一个列表到底部的时候,这个时候就会出现正在加载的底部加载布局去加载更多的数据。这里拿微信作为一个例子,如下图所示:

vcTjus3F89PRt6K1xNK70KnXtMysoaPV4srH0vLOqtXiuPbKsbrytPrC69Do0qq4+Lf+zvHG97eiy83H68fzu/HIocr9vt2yorPKz9bV4tCpyv2+3aGj1eK49sqxuvK78cihyv2+3b7Ns8nBy9fuusTKsbXEzsrM4qGjzqrKssO01eLDtMu1o7/I57n7w7vT0LfW0rO809TYtcS5psTco6zEx8O0o6zE47/PtqjQ6NKqu/HIocirsr+1xMr9vt2jrMTjv8nS1M/rz+ujrLrDvLjE6rXEyv2+3aOsyv2+3cG/v8myu8nZsKGjobeix+vH88ilu/HIodXi0KnK/b7dsqKzys/Wy/zDx8rHu+G63LrEyrG85LXEoaPL+dLUt9bSs7zT1Ni+zbrcusO1xL3ivvbBy9XiuPbOyszioaPE48/Iu/HIocbk1tC1xMquvLjM9cr9vt2yorPKz9bL/MPHoaO1scTj0rvWsbTTzbfkr8DA1eLKrry4zPXK/b7dtb294cr4tcTKsbryo6zV4rj2yrG68tTZyKW809TYuPy24LXEyv2+3bKis8rP1sv8w8eho8jnyc/NvMv5yr6jrNXi0fmyxcrHusO1xNPDu6fM5dHpoaM8L3A+DQo8aHIgLz4NCrjFxO7H5c76uvOjrL7fzOXKtc/WtcSyv7fWtb3By6Gj1eLA78q1z9bOotDFtcTPwsCtvNPU2NCnufujqLj2yMu40L71utyyu7Tto6y88r3gw/fBy6Opo6y087jF0OjSqtLUz8K8uLj2sr3W6KO6PGJyIC8+DQpmaXJzdCAmbWRhc2g7IMrXz8i5ub2oz8LArbzT1NjKsbXEtdeyv7zT1NiyvL7Wo6jV4sDvw/zD+86qdmlld19tb3Jlo6kgc2Vjb25kICZtZGFzaDsgu/HIocr9vt2yorj4bGlzdFZpZXfJ6NbDYWRhcHRlcqO7yejWw7rDYWRhcHRlcrrzo6y199PDt723qKO6PGNvZGU+bGlzdFZpZXcuYWRkRm9vdGVyVmlldyh2aWV3X21vcmUpOy8vIFRPRE8gzO2807XXsr+8x9TYsry+1jwvY29kZT7U2c35bGlzdFZpZXe1xLXXsr/M7bzTtdeyv7zT1NiyvL7WoaPX7rrzttRsaXN0Vmlld8no1sO7rLavvODM/cb3o7o8Y29kZT5saXN0Vmlldy5zZXRPblNjcm9sbExpc3RlbmVyKHRoaXMpOy8vIFRPRE8gbGlzdFZpZXfV4srHu6y2r7zgzP08L2NvZGU+ILKi1tjQtM/gudi3vbeoo7o8YnIgLz4NCjxjb2RlPnB1YmxpYyB2b2lkIG9uU2Nyb2xsU3RhdGVDaGFuZ2VkKEFic0xpc3RWaWV3IHZpZXcsIGludCBzY3JvbGxTdGF0ZSkge308L2NvZGU+ILrNIDxjb2RlPnB1YmxpYyB2b2lkIG9uU2Nyb2xsKEFic0xpc3RWaWV3IHZpZXcsIGludCBmaXJzdFZpc2libGVJdGVtLGludCB2aXNpYmxlSXRlbUNvdW50LCBpbnQgdG90YWxJdGVtQ291bnQpIHt9PC9jb2RlPiDV4sG9uPbW2NC0tcS3vbeo0ru49srHvODM/Wxpc3RWaWV3tcS7rLav17TMrLjEseSjrMHt0ru49srHvODM/Wxpc3RWaWV3tcS7rLavoaMgdGhpcmQgJm1kYXNoOyC1sbustq+84Mz9yejWw7rDuvOjrNTa1tjQtLXEwb249re9t6jA78PmxdC2z2xpc3RWaWV3yse38bustq+1vbXXsr+yosfSzaPWubustq+jqLy0u6y2r9e0zKzOqs2j1rm7rLavo6mho8jnufu0y8qxwvrX49XiuPbM9bz+o6zEx8O0vs2809TYuPy24LXEyv2+3aGjyv2+3bzT1NjN6rPJuvO+zcui0MLK/b7d1LSjrLTLyrG74dPQuPy24LXEyv2+3dTatdeyv7P2z9ahoyBmb3VydGggJm1kYXNoOyDX7rrztbHK/b7dyKuyv7zT1Ni6w7rzo6zSxrP9tdq2/rK91tDM7bzTtcS117K/vNPU2LK8vtZ2aWV3X21vcmWjrLX308O3vbeoo7o8Y29kZT5saXN0Vmlldy5yZW1vdmVGb290ZXJWaWV3KHZpZXdfbW9yZSk7Ly8gVE9ETyDSxrP9tdeyv7XEvNPU2LK8vtY8L2NvZGU+DQo8aDQgaWQ9"下面写代码一步一步来实现">下面写代码一步一步来实现: 1、首先准备一个底部加载布局,命名为view_more




    

    

很简单的布局,显示了一个进度条和一个文本控件。如图:

第二,给listView设置数据并设置滑动监听,设置好后判断是否滑动到listView的底部并停止滑动,如果是那么加载更多的数据:
package com.example.drop_down_load;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity implements OnScrollListener {

    private ListView listView;
    private int totalCount;// 数据总条数
    private List lists = new ArrayList();
    private ArrayAdapter adapter;
    // 创建handler接收消息并处理消息
    private Handler handler = new Handler() {

        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 0:
                // 创建adapter
                adapter = new ArrayAdapter(MainActivity.this,
                        android.R.layout.simple_list_item_1, lists);
                // 设置adapter
                listView.setAdapter(adapter);
                // 添加底部加载布局
                listView.addFooterView(view_more);
                // 设置监听
                setListeners();
                break;
            }
        };
    };
    private View view_more;
    private ProgressBar pb;
    private TextView tvLoad;
    private int lastVisibleIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 控件初始化
        initViews();
        // 初始化数据
        initData();
    }

    private void initData() {
        // 模拟网络请求获取数据,一次获取15条
        new Thread() {
            public void run() {
                try {
                    totalCount = 100;// 假设数据一共有100条,将来调接口可以获取到这个值
                    for (int i = 0; i < 15; i++) {
                        lists.add("数据" + (i + 1));
                    }
                    // 给handler发消息更新UI,子线程不可以更新UI
                    Message message = new Message();
                    message.what = 0;
                    handler.sendMessage(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();
    }

    private void setListeners() {
        if (totalCount > 15) {
            // listView设置滑动简监听
            listView.setOnScrollListener(this);
        } else {
            // 假如数据总数少于等于15条,直接移除底部的加载布局,不需要再加载更多的数据
            listView.removeFooterView(view_more);
        }
    }

    private void initViews() {
        listView = (ListView) findViewById(R.id.listView);
        // 构建底部加载布局
        view_more = (View) getLayoutInflater()
                .inflate(R.layout.view_more, null);
        // 进度条
        pb = (ProgressBar) view_more.findViewById(R.id.progressBar);
        // “正在加载...”文本控件
        tvLoad = (TextView) view_more.findViewById(R.id.tv_Load);
    }

    /**
     * 监听listView的滑动状态的改变
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        Log.e("TAG", "lastVisibleIndex = " + lastVisibleIndex);
        Log.e("TAG", "adapter.getCount() = " + adapter.getCount());
        // 滑到底部后自动加载,判断listView已经停止滚动并且最后可视的条目等于adapter的条目
        // 注意这里在listView设置好adpter后,加了一个底部加载布局。
        // 所以判断条件为:lastVisibleIndex == adapter.getCount()
        if (scrollState == SCROLL_STATE_IDLE
                && lastVisibleIndex == adapter.getCount()) {
            /**
             * 这里也要设置为可见,是因为当你真正从网络获取数据且获取失败的时候。
             * 我在失败的方法里面,隐藏了底部的加载布局并提示用户加载失败。所以再次监听的时候需要
             * 继续显示隐藏的控件。因为我模拟的获取数据,失败的情况这里不给出。实际中简单的加上几句代码就行了。
             */
            pb.setVisibility(View.VISIBLE);
            tvLoad.setVisibility(View.VISIBLE);
            loadMoreData();// 加载更多数据
        }
    }

    private void loadMoreData() {

    }

    /**
     * 监听listView的滑动
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        // 计算最后可见条目的索引
        lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;
        // 当adapter中的所有条目数已经和要加载的数据总条数相等时,则移除底部的View
        if (totalItemCount == totalCount + 1) {
            // 移除底部的加载布局
            listView.removeFooterView(view_more);
        }

    }

}

以上代码就是我上面步骤2和步骤2中所说的东西。加上我写了注释,所以相信大家看起来很简单。关键点是怎么判断listView是否滑动到了底部并停止了滑动。我在代码中添加了两行log,可以打印日志信息。大家去自己调试就能明白我对关键点是怎么判断的了,但是也有聪明的!嘿嘿!大家都懂,自己人,我就不接话了。如图:

最后就是加载更多的数据了,即完成第二步中未完成的方法:
loadMoreData();// 加载更多数据

具体代码实现为:

private void loadMoreData() {
        // 获取此时adapter中的总条目数
        int count = adapter.getCount();
        // 一次加载15条数据,即下拉加载的执行
        if (count + 15 < totalCount) {
            start = count;
            end = start + 15;
            initData(start, end);// 模拟网络获取数据操作
        } else {// 数据不足15条直接加载到结束
            start = count;
            end = totalCount;
            initData(start, end);// 模拟网络获取数据曹祖
            // 数据全部加载完成后,移除底部的view
            listView.removeFooterView(view_more);
            Toast.makeText(MainActivity.this, "数据已经全部加载", 1).show();
        }

    }


private void initData(final int start, final int end) {
        // 模拟网络请求获取数据,一次获取15条
        new Thread() {
            public void run() {
                try {
                    Thread.sleep(4000);// 模拟获取数据时的耗时3s
                    for (int i = start; i < end; i++) {
                        lists.add(i, "数据" + (i + 1));
                    }
                    // 给handler发消息更新UI,子线程不可以更新UI
                    Message message = new Message();
                    message.what = 1;
                    handler.sendMessage(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();
    }

此时handler中还要再加一个case语句,用来刷新数据源,如图红色方框标注地方,大家自己加一下。最后我会给项目源码,大家可以下载看我的代码:

好了下面给出几张项目的展示图片:

15条数据后加载更多数据,如图:

30条数据后加载更多数据,如图:

45条数据后加载更多数据,如图:

数据全部加载完后,移除底部加载布局,如图:

谈谈我的感悟:你需要有自己的想法思路,别人的东西可以借鉴,但是你需要从中学到点什么。要是什么都没学到,那就失去了分享的意义了!分享是为了让大家学到更多,收获更多。希望我的这篇能够给大家一点点收获!

以上就是Android中listView的下拉加载功能实现的全部内容,请多关注【51DEV】IT技术开发者社区。