您的位置:首页 > 产品设计 > UI/UE

Android UI组件----自定义ListView实现动态刷新

2014-08-13 16:52 288 查看
【声明】

欢迎转载,但请保留文章原始出处→_→

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:/article/4579381.html

联系方式:smyhvae@163.com

【正文】

一、具体步骤:

(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()

【工程文件】

链接:http://pan.baidu.com/s/1hqmoL1a
密码:bqsy
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: