【声明】
欢迎转载,但请保留文章原始出处→_→
生命壹号:http://www.cnblogs.com/smyhvae/
文章来源:http://www.cnblogs.com/smyhvae/p/3910541.html
【正文】
一、具体步骤:
(1)在activiy_main.xml中加一个ListView控件;再添加一个item的模板activity_main_item.xml,加一个底部加载的视图activity_main_load.xml;
(2)初始化item中的数据;
(3)自定义适配器BaseAdapter;
(4)ListiView绑定监听器OnScrollListener,并实现该监听器的两个方法:
- public void onScrollStateChanged(AbsListView view, int scrollState)
- public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount)
注:如果屏幕滑到最下面了,并且scrollState的状态为:滚动完毕之后ListView处于停止状态(手离开屏幕),此时可以加载新数据了
(5)通过额外的线程,来模拟加载新数据;
(6)新数据加载完成后,通过handle通知主线程,将这个新数据显示在UI界面上(因为涉及到线程安全问题),此时要调用notifyDataSetChanged()方法来刷新。
注:handler为线程之间通信的桥梁
二、代码实现:
完整版代码如下:
activiy_main.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
注:为优化起见,第9行的代码一定要写成"match_parent",而不是“wrap_content”(解释略)
activity_main_item.xml代码如下:(作为一个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/textView1_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textView2_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
activity_main_load.xml代码如下:(作为加载时底部的显示)
<?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="wrap_content"
android:orientation="horizontal"
android:gravity="center" > <ProgressBar
android:id="@+id/progressBar1"
android:layout_width="25dp"
android:layout_height="25dp" /> <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载···" /> </LinearLayout>
MainActivity.java代码如下:
package com.smyhvae.smyh005listview5; import java.util.Vector; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView; public class MainActivity extends Activity { private ListView listView;
Vector<News> news = new Vector<News>();
//private ArrayList<News> news = new ArrayList<News>();上面一行与这一行,二选一
MyAdapter myAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.listView1); listView.setOnScrollListener(new ListViewListener()); //绑定监听器 //设置底部视图
View footer = getLayoutInflater().inflate(R.layout.activity_main_load, null);
listView.addFooterView(footer); // initData();
new LoadDataThread().start();//加载数据的工作线程 myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
} //定义一个数据的类
class News {
String title;
String content;
} int index = 1;//数据的记数器(索引)
//初始化数据
void initData(){
System.out.println("initData");
for (int i = 0; i < 15; i++) {
News n = new News(); //这句话一定要放在循环的里面,否则每个item显示的内容都是一样的
n.title = "title-"+index;
n.content = "content"+index;
index++;
news.add(n); //这一步很关键,我就是少了这一步,导致运行时,界面为空
}
} //自定义适配器
class MyAdapter extends BaseAdapter{ @Override
public int getCount() {
// TODO Auto-generated method stub
return news.size();
}
public Object getItem(int position) {
return news.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = new ViewHolder();
//通过下面的条件判断语句,来循环利用。如果convertView = null ,表示屏幕上没有可以被重复利用的对象。
if(convertView==null){
//创建View
convertView = getLayoutInflater().inflate(R.layout.activity_main_item, null);
viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.textView1_title);
viewHolder.tvContent = (TextView) convertView.findViewById(R.id.textView2_content);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
//从Vector中取出数据填充到ListView列表项中
News n = news.get(position);
viewHolder.tvTitle.setText(n.title);
viewHolder.tvContent.setText(n.content);
return convertView;
} } static class ViewHolder{
TextView tvTitle;
TextView tvContent;
} //实现ListView的监听器的接口
int visibleLastIndex = 0; //最后一个显示的索引
public class ListViewListener implements OnScrollListener{
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//如果屏幕滑到最下面了,并且scrollState的状态为:滚动完毕之后ListView处于停止状态(手离开屏幕),
if(visibleLastIndex==myAdapter.getCount() && scrollState==OnScrollListener.SCROLL_STATE_IDLE){
new LoadDataThread().start();//如果满足上面的条件,此时,可以加载新数据了
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
visibleLastIndex = firstVisibleItem+visibleItemCount-1; } } //额外开启一个线程,模拟加载数据
class LoadDataThread extends Thread{
@Override
public void run() {
initData();
try {
Thread.sleep(2000);//休眠两秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //新数据加载完成后,通过handle通知主线程,将这个新数据显示在UI界面上(因为涉及到线程安全问题)
handler.sendEmptyMessage(1);
}
} //handler为线程之间通信的桥梁
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch(msg.what){
case 1: //根据上面的提示,当Message为1,表示数据处理完了,可以通知主线程了
myAdapter.notifyDataSetChanged(); //这个方法一旦调用,UI界面就刷新了
break; default :
break;
}
} }; @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} }
运行后,显示结果如下:
下图依次为:刚运行时、滑动到底部时、刷新之后的效果
三、总结:
- 监听事件处理的接口:OnScrollListener
- Adapter的刷新方法:notifyDataSetChanged()
【工程文件】
我的公众号
想学习代码之外的软技能?不妨关注我的微信公众号:生命团队(id:vitateam)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外: