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

首先,写一个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代码,在里面实现分页效果:

1 packagecom.szy.listviewdemo;
2  
3 importjava.util.ArrayList;
4 importjava.util.HashMap;
5  
6 importandroid.app.Activity;
7 importandroid.os.Bundle;
8 importandroid.os.Handler;
9 importandroid.view.View;
10 importandroid.view.View.OnClickListener;
11 importandroid.widget.AbsListView;
12 importandroid.widget.AbsListView.OnScrollListener;
13 importandroid.widget.Button;
14 importandroid.widget.ListView;
15 importandroid.widget.ProgressBar;
16 importandroid.widget.SimpleAdapter;
17 importandroid.widget.Toast;
18  
19 /**
20  * @author coolszy
21  * @date 2012-2-10
23  */
24 publicclass MainActivity extendsActivity implementsOnScrollListener
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  privateint MaxDateNum;
37  // 最后可见条目的索引
38  privateint lastVisibleIndex;
39  
40  @Override
41  publicvoid onCreate(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    publicvoid onClick(View v)
75    {
76     progressBar.setVisibility(View.VISIBLE);// 将进度条可见
77     btn.setVisibility(View.GONE);// 按钮不可见
78     handler.postDelayed(newRunnable()
79     {
80      @Override
81      publicvoid run()
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  privatevoid loadMoreDate()
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  publicvoid onScroll(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  publicvoid onScrollStateChanged(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条时加载剩余的)。


猜你喜欢

转载自blog.csdn.net/u010551217/article/details/23753755