实现ListView的分页加载功能

实现ListView的分页加载功能

2012年02月13日 ⁄ Android 编程暂无评论 ⁄ 被围观 6,215 次+

若水工作室

上图是一个新闻客户端的显示界面,新闻的信息是显示在ListView的控件中,我们知道要显示的新闻会很多,我们不可能每次都加载进来,因此我们这时需要进行分页处理。

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

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

查看源代码     打印     帮助

1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns: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<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns: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<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns: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代码,在里面实现分页效果:

查看源代码     打印     帮助

1package com.szy.listviewdemo;
2  
3import java.util.ArrayList;
4import java.util.HashMap;
5  
6import android.app.Activity;
7import android.os.Bundle;
8import android.os.Handler;
9import android.view.View;
10import android.view.View.OnClickListener;
11import android.widget.AbsListView;
12import android.widget.AbsListView.OnScrollListener;
13import android.widget.Button;
14import android.widget.ListView;
15import android.widget.ProgressBar;
16import android.widget.SimpleAdapter;
17import android.widget.Toast;
18  
19/**
20 * @author  coolszy
21 * @date 2012-2-10
22 * @blog  http://blog.92coding.com
23 */
24public class MainActivity extends Activity implements OnScrollListener
25{
26  
27 private SimpleAdapter simpleAdapter;
28 private ListView lv;
29 private Button btn;
30 private ProgressBar progressBar;
31 private ArrayList<HashMap<String, String>> list;
32 // ListView底部View
33 private View moreView;
34 private Handler handler;
35 // 设置一个最大的数据条数,超过即不再加载
36 private int MaxDateNum;
37 // 最后可见条目的索引
38 private int lastVisibleIndex;
39  
40 @Override
41 public void 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 = new Handler();
52  //初始化10条数据
53  list = new ArrayList<HashMap<String, String>>();
54  for (int i = 0; i < 10; i++)
55  {
56   HashMap<String, String> map = new HashMap<String, String>();
57   map.put("itemTitle", "第" + i + "行标题");
58   map.put("itemText", "第" + i + "行内容");
59   list.add(map);
60  }
61  // 实例化SimpleAdapter
62  simpleAdapter = new SimpleAdapter(this, list, R.layout.item, new String[]
63   { "itemTitle", "itemText" }, new int[]
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(new OnClickListener()
72  {
73   @Override
74   public void onClick(View v)
75   {
76    progressBar.setVisibility(View.VISIBLE);// 将进度条可见
77    btn.setVisibility(View.GONE);// 按钮不可见
78    handler.postDelayed(new Runnable()
79    {
80     @Override
81     public void 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 private void loadMoreDate()
96 {
97  int count = simpleAdapter.getCount();
98  if (count + 5 < MaxDateNum)
99  {
100   // 每次加载5条
101   for (int i = count; i < count + 5; i++)
102   {
103    HashMap<String, String> map = new HashMap<String, String>();
104    map.put("itemTitle", "新增第" + i + "行标题");
105    map.put("itemText", "新增第" + i + "行内容");
106    list.add(map);
107   }
108  } else
109  {
110   // 数据已经不足5条
111   for (int i = count; i < MaxDateNum; i++)
112   {
113    HashMap<String, String> map = new HashMap<String, String>();
114    map.put("itemTitle", "新增第" + i + "行标题");
115    map.put("itemText", "新增第" + i + "行内容");
116    list.add(map);
117   }
118  }
119  
120 }
121  
122 @Override
123 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
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 public void onScrollStateChanged(AbsListView view, int scrollState)
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条时加载剩余的)。

看下效果图:

若水工作室

若水工作室

示例代码下载地址:

http://115.com/file/c2dfxva5

 

 

 

 

 

昨天我也遇到这个问题,也在网上查找了很多资料,大概有两种方案,一种就是自定义GridView,就是extends它,或者extends RelativeLayout,然后自己实现它。网上能找出来的资料基本上都是这种。还有一种方案,用ListView来实现。假设你的GridView有3列,假如是三张ImageView吧,那你在自定义ListView的Item的时候,就得有3个ImageView。当然还得修改Adapter中的getCount方法,类似于这样:

   

      
      
public int getCount() {      if (photos.size() % 3 == 0) {          return photos.size() / 3;      }      return photos.size() / 3 + 1;  }

然后getView也会有相应的修改,无非就是根据position来计算吧,这里给个公式:当前行的第一个ImageView的位置是position3,第二个ImageView是position3+1,第三个是position*3+2

然后为每个ImageView设置onClickListener监听,这个可以从自定义的Adapter的构造方法中传过来。因为要取得当前点击的某个ImageView的数据,所以给每个ImageView设置一个Tag对象,这里直接把当前的Photo设置给ImageView的Tag。这里,在onClick(View v)中,通过Photo photp = v.getTag()就可以取得当前所点击的ImageView的数据,也就可以向其它页面传数据了。
大概原理是这样,我这项目里面还有动态选中和批量删除功能。代码量比较大,就不贴了,有什么问题再问吧。我这里测试工程里面的效果如下所示,看看是不是你需要的。

请输入图片描述

转载于:https://my.oschina.net/u/586684/blog/219983

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值