zoukankan      html  css  js  c++  java
  • 实现listview的分页加载

    上篇博文和大家分享了下拉刷新,这是一个用户体验非常好的操作方式。新浪微薄就是使用这种方式的典型。

    还有个问题,当用户从网络上读取微薄的时候,如果一下子全部加载用户未读的微薄这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这时候,我们就需要用到另一个功能,那就是listview的分页了。通过分页分次加载数据,用户看多少就去加载多少。

    通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下这个功能的实现。

    首先,写一个xml文件,moredata.xml,该文件即定义了放在listview底部的视图:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width
    ="match_parent"
    android:layout_height
    ="match_parent"
    android:orientation
    ="vertical" >
    <Button
    android:id="@+id/bt_load"
    android:layout_width
    ="fill_parent"
    android:layout_height
    ="wrap_content"
    android:text
    ="加载更多数据" />
    <ProgressBar
    android:id="@+id/pg"
    android:layout_width
    ="wrap_content"
    android:layout_height
    ="wrap_content"
    android:layout_gravity
    ="center_horizontal"
    android:visibility
    ="gone"
    />
    </LinearLayout>

    可以看到是一个按钮和一个进度条。因为只做一个演示,这里简单处理,通过设置控件的visibility,未加载时显示按钮,加载时就显示进度条。

    写一个item.xml,大家应该很熟悉了。用来定义listview的每个item的视图。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width
    ="match_parent"
    android:layout_height
    ="match_parent"
    android:orientation
    ="vertical" >

    <TextView
    android:id="@+id/tv_title"
    android:textSize
    ="20sp"
    android:layout_width
    ="wrap_content"
    android:layout_height
    ="wrap_content"
    android:layout_marginTop
    ="5dp"
    />
    <TextView
    android:textSize="12sp"
    android:id
    ="@+id/tv_content"
    android:layout_width
    ="wrap_content"
    android:layout_height
    ="wrap_content"
    android:layout_marginTop
    ="5dp"
    />

    </LinearLayout>

    main.xml就不贴了,整个主界面就一个listview。

    直接先看下Activity的代码,在里面实现分页效果。

    package com.notice.moredate;

    import java.util.ArrayList;
    import java.util.HashMap;

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.Button;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.SimpleAdapter;
    import android.widget.Toast;

    public class MoreDateListActivity extends Activity implements OnScrollListener {

    // ListView的Adapter
    private SimpleAdapter mSimpleAdapter;
    private ListView lv;
    private Button bt;
    private ProgressBar pg;
    private ArrayList<HashMap<String,String>> list;
    // ListView底部View
    private View moreView;
    private Handler handler;
    // 设置一个最大的数据条数,超过即不再加载
    private int MaxDateNum;
    // 最后可见条目的索引
    private int lastVisibleIndex;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    MaxDateNum = 22; // 设置最大数据条数

    lv = (ListView) findViewById(R.id.lv);

    // 实例化底部布局
    moreView = getLayoutInflater().inflate(R.layout.moredate, null);

    bt = (Button) moreView.findViewById(R.id.bt_load);
    pg = (ProgressBar) moreView.findViewById(R.id.pg);
    handler = new Handler();

    // 用map来装载数据,初始化10条数据
    list = new ArrayList<HashMap<String,String>>();
    for (int i = 0; i < 10; i++) {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("ItemTitle", "第" + i + "行标题");
    map.put("ItemText", "第" + i + "行内容");
    list.add(map);
    }
    // 实例化SimpleAdapter
    mSimpleAdapter = new SimpleAdapter(this, list, R.layout.item,
    new String[] { "ItemTitle", "ItemText" },
    new int[] { R.id.tv_title, R.id.tv_content });
    // 加上底部View,注意要放在setAdapter方法前
    lv.addFooterView(moreView);
    lv.setAdapter(mSimpleAdapter);
    // 绑定监听器
    lv.setOnScrollListener(this);

    bt.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
    pg.setVisibility(View.VISIBLE);// 将进度条可见
    bt.setVisibility(View.GONE);// 按钮不可见

    handler.postDelayed(new Runnable() {

    @Override
    public void run() {
    loadMoreDate();// 加载更多数据
    bt.setVisibility(View.VISIBLE);
    pg.setVisibility(View.GONE);
    mSimpleAdapter.notifyDataSetChanged();// 通知listView刷新数据
    }

    }, 2000);
    }
    });

    }

    private void loadMoreDate() {
    int count = mSimpleAdapter.getCount();
    if (count + 5 < MaxDateNum) {
    // 每次加载5条
    for (int i = count; i < count + 5; i++) {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("ItemTitle", "新增第" + i + "行标题");
    map.put("ItemText", "新增第" + i + "行内容");
    list.add(map);
    }
    } else {
    // 数据已经不足5条
    for (int i = count; i < MaxDateNum; i++) {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("ItemTitle", "新增第" + i + "行标题");
    map.put("ItemText", "新增第" + i + "行内容");
    list.add(map);
    }
    }

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
    int visibleItemCount, int totalItemCount) {
    // 计算最后可见条目的索引
    lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;

    // 所有的条目已经和最大条数相等,则移除底部的View
    if (totalItemCount == MaxDateNum + 1) {
    lv.removeFooterView(moreView);
    Toast.makeText(this, "数据全部加载完成,没有更多数据!", Toast.LENGTH_LONG).show();
    }

    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    // 滑到底部后自动加载,判断listview已经停止滚动并且最后可视的条目等于adapter的条目
    if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
    && lastVisibleIndex == mSimpleAdapter.getCount()) {
    // 当滑到底部时自动加载
    // pg.setVisibility(View.VISIBLE);
    // bt.setVisibility(View.GONE);
    // handler.postDelayed(new Runnable() {
    //
    // @Override
    // public void run() {
    // loadMoreDate();
    // bt.setVisibility(View.VISIBLE);
    // pg.setVisibility(View.GONE);
    // mSimpleAdapter.notifyDataSetChanged();
    // }
    //
    // }, 2000);

    }

    }

    }

    通过注释,大家应该很容易理解了。这里做下简单的解析。首先要注意的是,addFootView方法一定要在setAdapter方法之前,否则会无效。addFootView方法为listview底部加入一个视图,在本例中就是那个Button加progressbar的视图。当用户点击按钮时,调用loadmoreDate方法,为listview绑定更多的数据,通过adapter的notifyDataSetChanged方法通知listview刷新,显示刚加入的数据。

    这里用handler异步延迟2秒操作,模仿加载过程。同时listview绑定了onScrollListener监听器,并且实现了onScroll和onScrollStateChanged方法。在后者方法中,我们通过判断listview已经停止滚动并且最后可视的条目等于adapter的条目,可以知道用户已经滑动到底部并且自动加载,代码中将这部分代码注释掉了,大家可以自己试下。

    代码中还加入了一个MaxDateNum变量,用来记录最大的数据数量。也就是说网络或者其他地方一共的数据。通过onScroll方法判断用户加载完这些数据后,移除listview底部视图,不让继续加载。同时在loadmoreDate方法中也对最大数据量做相应的操作来判断加载数量。(默认加载5条,不足5条时加载剩余的)。

    看下效果图:

       

       

    就写这么多了,总的来说还是很简单的,但是确实非常有用的一个效果。欢迎留言交流。

    原文:http://blog.csdn.net/notice520/article/details/7248094#

  • 相关阅读:
    UVA 10618 Tango Tango Insurrection
    UVA 10118 Free Candies
    HDU 1024 Max Sum Plus Plus
    POJ 1984 Navigation Nightmare
    CODEVS 3546 矩阵链乘法
    UVA 1625 Color Length
    UVA 1347 Tour
    UVA 437 The Tower of Babylon
    UVA 1622 Robot
    UVA127-"Accordian" Patience(模拟)
  • 原文地址:https://www.cnblogs.com/shanzei/p/2419396.html
Copyright © 2011-2022 走看看