ListView和AsyncTask结合实现下拉刷新

无疑,在Android开发中,ListView是使用非常频繁的控件之一,ListView提供一个列表的容易,允许我们以列表的形式将数据展示到界面上,但是Google给我们提供的原生ListView的控件,虽然在功能上很强大,但是在用户体验和动态效果上,还是比较差劲的。为了改善用户体验,市面上纷纷出现了各种各样的自定义的ListView,他们功能强大,界面美观,使我们该需要学习的地方。其中,使用最频繁的功能无疑就是ListView的下拉刷新和上拉加载数据了,几乎在每一款内容型的App中都可以找到这种控件的身影,尤其是需要联网获取数据的模块,使用的就更为频繁了,so,我们很有必要了解下这种效果是怎么实现的。

说白了实现ListView的下拉刷新和上拉加载数据的功能无非是对ListView实现加header和加footer,在适当的时候分别显示header和footer,然后又在适当的时候隐藏header和footer。主要是根据ListView的setPadding、addHeaderView和addFooterView等方法来实现。AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

        下面就ListView和AsyncTask如何实现数据加载和下拉刷新和上拉加载数据的具体代码,代码注释很详细:

源码下载源码下载

自定义MyListView :

package cn.zxw.pull.refresh.view;

import java.text.SimpleDateFormat;
import java.util.logging.SimpleFormatter;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import cn.zxw.pull.refresh.R;

public class MyListView extends ListView implements OnScrollListener {

	// 加载数据的接口
	public interface OnListViewLoadDataListener {

		public void onLoadNewData();

		// 加载更多数据
		public void onLoadMoreData();
	}

	private OnListViewLoadDataListener onListViewLoadDataListener;

	public void setOnListViewLoadDataListener(
			OnListViewLoadDataListener onListViewLoadDataListener) {
		this.onListViewLoadDataListener = onListViewLoadDataListener;
	}

	private static final String TAG = "MyListView";
	private View header;
	private ImageView iv_arrow;
	private ProgressBar pb;
	private TextView tv_state;
	private TextView tv_time;
	private int height;

	enum HeaderState {
		PULL_DOWN_REFRESH, // 下拉刷新
		RELEASE_REFRESH, // 释放刷新
		REFRESHING// 正在刷新
	}

	// 设置默认状态
	private HeaderState state = HeaderState.PULL_DOWN_REFRESH;
	// ListView头文字的信息
	private String[] stateInfos = new String[] { "下拉刷新", "释放刷新", "正在刷新" };

	public MyListView(Context context) {
		super(context);
	}

	public MyListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initHead();
		initFooter();
		setOnScrollListener(this);
	}

	/**
	 * 初始化footer
	 */
	private void initFooter() {

		footer = View.inflate(getContext(), R.layout.footer, null);
		footer.measure(0, 0);
		footerHeight = footer.getMeasuredHeight();
		footer.setPadding(0, -footerHeight, 0, 0);
		addFooterView(footer);
	}

	/**
	 * 初始化listview的头部
	 */
	private void initHead() {
		header = View.inflate(getContext(), R.layout.header, null);
		iv_arrow = (ImageView) header.findViewById(R.id.iv_arrow);
		pb = (ProgressBar) header.findViewById(R.id.pb);
		tv_state = (TextView) header.findViewById(R.id.tv_state);
		tv_time = (TextView) header.findViewById(R.id.tv_time);
		pb.setVisibility(View.INVISIBLE);// 隐藏pb
		addHeaderView(header);// 添加header,然后要隐藏header
		//int height = header.getHeight(); 如果一个控件没有显示 是无法获取宽高  layout
		header.measure(0, 0);//Android中控件的位置必须先测量
		height = header.getMeasuredHeight();//获取控件的高度
		header.setPadding(0, -height, 0, 0);// 隐藏控件,即是将控件设置在屏幕顶部之外
	}

	public MyListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	private boolean isLoadingData = false;// 是否加载更多数据

	// 滑动状态改变
	// 闲置和飞行状态 listview必须是已经显示到最后下处理
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		int lastVisiblePosition = getLastVisiblePosition();// 获取listview最后显示的下标
		int count = getAdapter().getCount();
		// 闲置状态和飞行状态 还必须是ListView已经显示到最后 没有在加载数据
		if ((scrollState == OnScrollListener.SCROLL_STATE_IDLE || scrollState == OnScrollListener.SCROLL_STATE_FLING)
				&& lastVisiblePosition == count - 1 && !isLoadingData) {
			isLoadingData = true;
			footer.setPadding(0, 0, 0, 0);
			// 脚其实还是没有显示
			setSelection(count);
			if (onListViewLoadDataListener != null) {
				onListViewLoadDataListener.onLoadMoreData();
			}

		}
		switch (scrollState) {
		case OnScrollListener.SCROLL_STATE_IDLE:// 闲置

			break;
		case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 滑动
			break;
		case OnScrollListener.SCROLL_STATE_FLING:// 飞行
			break;

		default:
			break;
		}
	}

	/**
	 * firstVisibleItem 屏幕上显示的第一个条目的下标 
	 *visibleItemCount 屏幕上显示的条目总数 
	 * totalItemCount 条目总数
	 */
	private int firstVisibleItem;// 记录第一个条目位置

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		this.firstVisibleItem = firstVisibleItem;
		Log.i(TAG, "firstVisibleItem:" + firstVisibleItem);

	}

	private int startY;
	private int footerHeight;
	private View footer;

	// 滑动改变header
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.i(TAG, "ACTION_DOWN");
			startY = (int) ev.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i(TAG, "ACTION_MOVE");
			// 显示的是第一个条目
			if (firstVisibleItem == 0 && state != HeaderState.REFRESHING) {
				int moveY = (int) ev.getY();
				int disY = moveY - startY;
				// 控制header的显示
				int top = -height + disY;
				if (top > 0 && state == HeaderState.PULL_DOWN_REFRESH) {// 原来是下拉刷新
																		// 现在置为释放刷新
					state = HeaderState.RELEASE_REFRESH;
					RotateAnimation animation = getRotateAnimation1();
					iv_arrow.setAnimation(animation);
					tv_state.setText(stateInfos[1]);
				} else if (top <= 0 && state == HeaderState.RELEASE_REFRESH) {
					// 原来是释放刷新 现在变为下拉刷新
					state = HeaderState.PULL_DOWN_REFRESH;
					RotateAnimation animation = getRotateAnimation2();
					iv_arrow.setAnimation(animation);
					tv_state.setText(stateInfos[2]);

				}
				header.setPadding(0, top, 0, 0);

			}
			break;
		case MotionEvent.ACTION_UP:
			Log.i(TAG, "ACTION_UP");
			// 用户松开手指:1 下拉刷新 2 释放刷新
			if (state == HeaderState.PULL_DOWN_REFRESH) {
				// 把头直接隐藏
				header.setPadding(0, -height, 0, 0);
			} else if (state == HeaderState.RELEASE_REFRESH) {
				// 把头显示在第一行 作为一个正常的显示
				// 把头的状态进行改变
				header.setPadding(0, 0, 0, 0);
				state = HeaderState.REFRESHING;
				iv_arrow.clearAnimation();// 清除动画
				iv_arrow.setVisibility(View.INVISIBLE);
				// 箭头无法隐藏:iv_arrow有动画
				pb.setVisibility(View.VISIBLE);
				tv_state.setText(stateInfos[2]);
				// 通知activity加载数据
				if (onListViewLoadDataListener != null) {
					onListViewLoadDataListener.onLoadNewData();
				}
			}
			break;

		default:
			break;
		}
		return super.onTouchEvent(ev);
	}

	public RotateAnimation getRotateAnimation1() {
		RotateAnimation rotateAnimation = new RotateAnimation(0, -180,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		rotateAnimation.setDuration(200);
		rotateAnimation.setFillAfter(true);
		return rotateAnimation;

	}

	public RotateAnimation getRotateAnimation2() {
		RotateAnimation rotateAnimation = new RotateAnimation(-180, -360,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		rotateAnimation.setDuration(200);
		rotateAnimation.setFillAfter(true);
		return rotateAnimation;

	}

	// 隐藏头
	// 1.状态改为下拉刷新
	// 2.隐藏进度条 显示箭头 修改文字
	// 3.刷新的事件
	// 4.header设置padding
	public void hideHeader() {
		state = HeaderState.PULL_DOWN_REFRESH;
		pb.setVisibility(View.INVISIBLE);
		iv_arrow.setVisibility(View.VISIBLE);
		tv_state.setText(stateInfos[0]);
		long mills = System.currentTimeMillis();
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String dateStr = format.format(mills);
		tv_time.setText("上次刷新的时间为:" + dateStr);
		header.setPadding(0, -height, 0, 0);
	}

	// 隐藏footer
	public void hideFooter() {
		footer.setPadding(0, -footerHeight, 0, 0);
		isLoadingData = false;
	}
}
MainActivity:
package cn.zxw.pull.refresh;

import java.util.ArrayList;
import java.util.List;

import cn.zxw.pull.refresh.view.MyListView;
import cn.zxw.pull.refresh.view.MyListView.OnListViewLoadDataListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.widget.ArrayAdapter;

public class MainActivity extends Activity implements
		OnListViewLoadDataListener {

	protected static final int SUCCESS_LOAD_NEW_DATA = 0;
	protected static final int SUCCESS_LOAD_MORE_DATA =1;
	private MyListView lv;
	private ArrayAdapter<String> adapter;
	private List<String> objects;
	Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SUCCESS_LOAD_NEW_DATA:
				String data = (String) msg.obj;
				objects.add(0,data);
				adapter.notifyDataSetChanged();
				lv.hideHeader();
				break;
				case SUCCESS_LOAD_MORE_DATA:
					List<String> list = (List<String>) msg.obj;
					objects.addAll(list);
					adapter.notifyDataSetChanged();
					lv.hideFooter();
					break;
			default:
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		lv = (MyListView) findViewById(R.id.lv);
		// 值的初始化
		objects = new ArrayList<String>();
		for (int i = 0; i < 13; i++) {
			objects.add("初始化的数据" + i);
		}
		adapter = new ArrayAdapter<String>(getApplication(),
				android.R.layout.simple_list_item_1, android.R.id.text1,
				objects);
		lv.setAdapter(adapter);
		lv.setOnListViewLoadDataListener(this);

	}

	@Override
	public void onLoadNewData() {

		new Thread() {
			public void run() {
				SystemClock.sleep(3000);
				String data = "加载的数据";
				Message msg = Message.obtain();
				msg.what = SUCCESS_LOAD_NEW_DATA;
				msg.obj = data;
				handler.sendMessage(msg);
			};
		}.start();
	}

	@Override
	public void onLoadMoreData() {
		new MyAsyncTask().execute("");
	}
	//Params 参数:一般都是要执行下载的路径  String    Progress    进度条的值 Integer, Result 结果 Bitmap  String  List<String>  
	private class MyAsyncTask extends AsyncTask<String , Integer, List<String>>{
		//准备
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}
		//执行后台的耗时操作
		@Override
		protected List<String> doInBackground(String... params) {
			SystemClock.sleep(3000);
			List<String> list=new ArrayList<String>();
			for (int i = 0; i <5; i++) {
				list.add("加载更多数据"+i);
			}
			return list;
		}
		//下载完成后
		@Override
		protected void onPostExecute(List<String> result) {
			super.onPostExecute(result);
			objects.addAll(result);
			adapter.notifyDataSetChanged();
			lv.hideFooter();
		}
		//必须是有另外一个方法的调用才会调用该方法 
	   //publishProgress()  该方法一般都是在doInBackground(String... params)里面调用
		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
		}
		
		
	}

}
如果想详细知道AsyncTask可以参考 scott's的博客


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值