ListView 加载数据实现分页加载功能

来源:互联网 发布:淘宝试用要还回去吗 编辑:程序博客网 时间:2024/04/29 08:24

首先,写一个xml文件,moredata.xml,该文件即定义了放在listview底部的视图,如上图的“加载更多”按钮:

1<?xmlversion="1.0"encoding="utf-8"?>
2<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3    android:layout_width="match_parent"
4    android:layout_height="match_parent"
5    android:orientation="vertical">
6  <Button   
7      android:id="@+id/bt_load"   
8      android:layout_width="fill_parent"   
9      android:layout_height="wrap_content" 
10      android:text="加载更多据"/>
11  <ProgressBar
12      android:id="@+id/progressBar"
13      android:layout_width="wrap_content"
14      android:layout_height="wrap_content"
15      android:layout_gravity="center_horizontal"
16      android:visibility="gone"
17      />
18</LinearLayout>

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

写一个item.xml,用来定义listview的每个item的视图:

1<?xmlversion="1.0"encoding="utf-8"?>
2<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3    android:layout_width="match_parent"
4    android:layout_height="match_parent"
5    android:orientation="vertical">
6    <TextView
7        android:id="@+id/tv_title"
8        android:textSize="20sp"
9        android:layout_width="wrap_content"
10        android:layout_height="wrap_content"
11        android:layout_marginTop="5dp"
12        />
13    <TextView
14        android:textSize="12sp"
15        android:id="@+id/tv_content"
16        android:layout_width="wrap_content"
17        android:layout_height="wrap_content"
18        android:layout_marginTop="5dp"
19        />
20</LinearLayout>

MainActivity的页面布局XML,main.xml:

1<?xmlversion="1.0"encoding="utf-8"?>
2<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3    android:layout_width="fill_parent"
4    android:layout_height="fill_parent"
5    android:orientation="vertical">
6    <ListView
7        android:id="@+id/lv"
8        android:layout_width="fill_parent"
9        android:layout_height="fill_parent"
10    />
11</LinearLayout>

下面我们看下MainActivity代码,在里面实现分页效果:

1packagecom.szy.listviewdemo;
2 
3importjava.util.ArrayList;
4importjava.util.HashMap;
5 
6importandroid.app.Activity;
7importandroid.os.Bundle;
8importandroid.os.Handler;
9importandroid.view.View;
10importandroid.view.View.OnClickListener;
11importandroid.widget.AbsListView;
12importandroid.widget.AbsListView.OnScrollListener;
13importandroid.widget.Button;
14importandroid.widget.ListView;
15importandroid.widget.ProgressBar;
16importandroid.widget.SimpleAdapter;
17importandroid.widget.Toast;
18 
19/**
20 * @author coolszy
21 * @date 2012-2-10
22 * @blog http://blog.92coding.com
23 */
24publicclassMainActivity extendsActivityimplementsOnScrollListener
25{
26 
27 privateSimpleAdapter simpleAdapter;
28 privateListView lv;
29 privateButton btn;
30 privateProgressBar progressBar;
31 privateArrayList<HashMap<String, String>> list;
32 // ListView底部View
33 privateView moreView;
34 privateHandler handler;
35 // 设置一个最大的数据条数,超过即不再加载
36 privateintMaxDateNum;
37 // 最后可见条目的索引
38 privateintlastVisibleIndex;
39 
40 @Override
41 publicvoidonCreate(Bundle savedInstanceState)
42 {
43  super.onCreate(savedInstanceState);
44  setContentView(R.layout.main);
45  MaxDateNum = 22;// 设置最大数据条数
46  lv = (ListView) findViewById(R.id.lv);
47  // 实例化底部布局
48  moreView = getLayoutInflater().inflate(R.layout.moredata, null);
49  btn = (Button) moreView.findViewById(R.id.bt_load);
50  progressBar = (ProgressBar) moreView.findViewById(R.id.progressBar);
51  handler = newHandler();
52  //初始化10条数据
53  list = newArrayList<HashMap<String, String>>();
54  for(inti = 0; i < 10; i++)
55  {
56   HashMap<String, String> map = newHashMap<String, String>();
57   map.put("itemTitle","第"+ i + "行标题");
58   map.put("itemText","第"+ i + "行内容");
59   list.add(map);
60  }
61  // 实例化SimpleAdapter
62  simpleAdapter = newSimpleAdapter(this, list, R.layout.item, newString[]
63   {"itemTitle","itemText"},newint[]
64   { R.id.tv_title, R.id.tv_content });
65  // 加上底部View,注意要放在setAdapter方法前
66  lv.addFooterView(moreView);
67  lv.setAdapter(simpleAdapter);
68   
69  // 绑定监听器
70  lv.setOnScrollListener(this);
71  btn.setOnClickListener(newOnClickListener()
72  {
73   @Override
74   publicvoidonClick(View v)
75   {
76    progressBar.setVisibility(View.VISIBLE);// 将进度条可见
77    btn.setVisibility(View.GONE);// 按钮不可见
78    handler.postDelayed(newRunnable()
79    {
80     @Override
81     publicvoidrun()
82     {
83      loadMoreDate();// 加载更多数据
84      btn.setVisibility(View.VISIBLE);
85      progressBar.setVisibility(View.GONE);
86      simpleAdapter.notifyDataSetChanged();// 通知listView刷新数据
87     }
88 
89    },2000);
90   }
91  });
92 
93 }
94 
95 privatevoidloadMoreDate()
96 {
97  intcount = simpleAdapter.getCount();
98  if(count + 5< MaxDateNum)
99  {
100   // 每次加载5条
101   for(inti = count; i < count + 5; i++)
102   {
103    HashMap<String, String> map = newHashMap<String, String>();
104    map.put("itemTitle","新增第"+ i + "行标题");
105    map.put("itemText","新增第"+ i + "行内容");
106    list.add(map);
107   }
108  }else
109  {
110   // 数据已经不足5条
111   for(inti = count; i < MaxDateNum; i++)
112   {
113    HashMap<String, String> map = newHashMap<String, String>();
114    map.put("itemTitle","新增第"+ i + "行标题");
115    map.put("itemText","新增第"+ i + "行内容");
116    list.add(map);
117   }
118  }
119 
120 }
121 
122 @Override
123 publicvoidonScroll(AbsListView view, intfirstVisibleItem,intvisibleItemCount,inttotalItemCount)
124 {
125  // 计算最后可见条目的索引
126  lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;
127  // 所有的条目已经和最大条数相等,则移除底部的View
128  if(totalItemCount == MaxDateNum + 1)
129  {
130   lv.removeFooterView(moreView);
131   Toast.makeText(this,"数据全部加载完成,没有更多数据!", Toast.LENGTH_LONG).show();
132  }
133 }
134 
135 @Override
136 publicvoidonScrollStateChanged(AbsListView view, intscrollState)
137 {
138  // 滑到底部后自动加载,判断listview已经停止滚动并且最后可视的条目等于adapter的条目
139  if(scrollState == OnScrollListener.SCROLL_STATE_IDLE && lastVisibleIndex == simpleAdapter.getCount())
140  {
141   // 当滑到底部时自动加载
142   // progressBar.setVisibility(View.VISIBLE);
143   // btn.setVisibility(View.GONE);
144   // handler.postDelayed(new Runnable() {
145   //
146   // @Override
147   // public void run() {
148   // loadMoreDate();
149   // btn.setVisibility(View.VISIBLE);
150   // progressBar.setVisibility(View.GONE);
151   // simpleAdapter.notifyDataSetChanged();
152   // }
153   //
154   // }, 2000);
155  }
156 }
157}

通过注释,大家应该很容易理解了。这里做下简单的解析。首先要注意的是,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条时加载剩余的)。


0 0