Android 动态加载 ListView 实现

首先讲原理:

ListView 可以设置一个滚动监听器

android.widget.AbsListView.setOnScrollListener(OnScrollListener l)
有个方法


public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
这里面有三个参数:
firstVisibleItem: 第一个可见Item在所有Item中的位置(即屏幕上显示的第一行,在你的数据数组中的位置)
visibleItemCount: 可见Item个数(屏幕内可以显示多少行)
totalItemCount: 总共有多少行数据
通过这个3个参数容易想到,如果  firstVisibleItem +  visibleItemCount >=  totalItemCount 不就表明 列表已经滑到了底部么?这个时候就是我们加载数据的时机了!


然后我们需要在列表底部增加一个 item 显示:点击加载更多 或者 正在加载中请稍后 或者 没有更多数据了
这个我们要用到

ListView.addFooterView(View v)

添加了 footView ,footView 就成了列表最后一行,也就说相对于你的总数据增加了一行,所有这里有一点要注意的地方:
调用这个方法必须在 ListView.SetAdapter() 之前,否则将会影响 Cursor 类适配器

知道了原理就很简单了,下面奉上我封装的 LoaderListView

/**
 * 下拉自动加载的 Listview 
 * 
 * @author Yichou
 * @创建日期 2013-3-19 16:01:10
 * 
 * 2013-6-30
 */
public class LoaderListView extends ListView implements 
		OnScrollListener, 
		OnItemClickListener,
		OnClickListener {
	public interface LoadNotifyer {
		public void load();
	}
	
	public interface OnScrollStateChangedListener {
		public void onScrollStateChanged(int oldState, int newState);
	}
	
	private LinearLayout footViewLoading, footViewRetry, footViewNomore;
	private LoadNotifyer loadNotifyer;
	private int scrollState;
	private OnScrollStateChangedListener onScrollStateChangedListener;
	

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

	public LoaderListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public LoaderListView(Context context) {
		super(context);
		init(context);
	}
	
	@Override
	public void onClick(View v) {
		if(v.getId() == 0x1001){ //重新加载
			setFootviewType(FOOTVIEW_TYPE.LOADING);
			if(loadNotifyer != null)
				loadNotifyer.load();
		}else if (v.getId() == 0x1002) {
			setSelection(0);
		}
	}
	
	private void init(Context context) {
		footViewLoading = new LinearLayout(context);
		footViewLoading.setOrientation(LinearLayout.HORIZONTAL);
		footViewLoading.setGravity(Gravity.CENTER);
		ProgressBar bar = new ProgressBar(context);
		TextView textView = new TextView(context);
		textView.setText("加载中...");
		footViewLoading.addView(bar, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		footViewLoading.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		
		footViewRetry = new LinearLayout(context);
		footViewRetry.setOrientation(LinearLayout.HORIZONTAL);
		footViewRetry.setGravity(Gravity.CENTER);
		textView = new TextView(context);
		textView.setId(0x1001);
		textView.setGravity(Gravity.CENTER);
		textView.setText("网络不给力,请重试 o(︶︿︶)o");
		textView.setOnClickListener(this);
		footViewRetry.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, getFixPx(50)));
		
		footViewNomore = new LinearLayout(context);
		footViewNomore.setOrientation(LinearLayout.HORIZONTAL);
		footViewNomore.setGravity(Gravity.CENTER);
		footViewNomore.setId(0x1002);

		textView = new TextView(context);
		textView.setText("返回顶部↑");
		textView.setGravity(Gravity.CENTER);
		
		footViewNomore.setClickable(true);
		footViewNomore.setOnClickListener(this);
		footViewNomore.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, getFixPx(50)));
		
		setFootviewType(FOOTVIEW_TYPE.LOADING);
		
		setOnScrollListener(this);
		scrollState = SCROLL_STATE_IDLE;
		
		super.setOnItemClickListener(this);
	}
	
	public enum FOOTVIEW_TYPE {
		/** 加载中 */
		LOADING, 
		/** 没有更多了,返回顶部 */
		NOMOR, 
		/** 加载失败重试 */
		RETRY,
		/**无*/
		NONE
	}
	
	private View curFootView;
	public void setFootviewType(FOOTVIEW_TYPE type) {
		if(curFootView != null && curFootView.getTag() == type)
			return;
		
		if(curFootView != null)
			removeFooterView(curFootView);
		
		switch (type) {
		case LOADING:
			curFootView = footViewLoading;
			break;
		case NOMOR:
			curFootView = footViewNomore;
			break;
		case RETRY:
			curFootView = footViewRetry;
			break;
		case NONE:
			return;
		}
		
		addFooterView(curFootView);
		curFootView.setTag(type);
	}

	private View curHeadView;
	public void setHeadView(View v) {
		if(curHeadView!=null)
			return;
		curHeadView=v;
		addHeaderView(v);
	}
	
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if (scrollState != this.scrollState) {
			if(onScrollStateChangedListener != null){
				onScrollStateChangedListener.onScrollStateChanged(this.scrollState, scrollState);
			}
			this.scrollState = scrollState;
		}
	}

	protected int firstVisibleItem, visibleItemCount, totalItemCount;
	
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
		if(totalItemCount < 2 ) //footview 也算
			return;
		
//		System.out.println("first=" + firstVisibleItem + ",visible=" + visibleItemCount + ",total=" + totalItemCount);
		
		if(firstVisibleItem + visibleItemCount >= totalItemCount){ //说明 footView 可见,通知加载更多
			if (loadNotifyer != null && (curFootView != footViewNomore)) {
				loadNotifyer.load();
			}
		}
		this.firstVisibleItem = firstVisibleItem;
		this.visibleItemCount = visibleItemCount;
		this.totalItemCount = totalItemCount;
	}
	
	public int getFirstVisibleItem() {
		return firstVisibleItem;
	}
	
	public int getVisibleItemCount() {
		return visibleItemCount;
	}
	
	public int getScrollState() {
		return scrollState;
	}
	
	public void setLoadNotifyer(LoadNotifyer loadNotifyer) {
		this.loadNotifyer = loadNotifyer;
	}
	
	public void setOnScrollStateChangedListener(OnScrollStateChangedListener onScrollStateChangedListener) {
		this.onScrollStateChangedListener = onScrollStateChangedListener;
	}
	
	public int getFixPx(int dp){
		float scale=getContext().getResources().getDisplayMetrics().density;
		return (int)(scale*dp+0.5);
	}

	private OnItemClickListener listener;
	@Override
	public void setOnItemClickListener(OnItemClickListener listener) {
		this.listener = listener;
//		super.setOnItemClickListener(listener);
	}
	
	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
		if(listener==null)return;
		if(curHeadView != null){
			if(position==0)return;
			listener.onItemClick(parent, view, position-1, id);
		}else{
			listener.onItemClick(parent, view, position, id);
		}
	}
}

使用很方便,只需调用
LoaderListView.setLoadNotifyer(LoadNotifyer loadNotifyer)
然后每次滑到底部需要加载更多数据的时候,就会回调 
LoadNotifyer.load()
然后你在 load() 方法里加载下一页数据,加载完毕调用 
Adapter.notifyDataSetChanged()
列表就展示新数据了!

此外我这里面还封装了一个神奇的功能是设置 FootView 状态:
这里有四种状态:

public enum FOOTVIEW_TYPE {
		/** 加载中 */
		LOADING, 
		/** 没有更多了,返回顶部 */
		NOMOR, 
		/** 加载失败重试 */
		RETRY,
		/**无*/
		NONE
	}
在加载下一页失败的时候,调用
listView.setFootviewType(FOOTVIEW_TYPE.RETRY)
列表底部显示改为,加载失败,点击重试,用户点击之后,会再次回调你的 load() 方法


同理
当你没有更多数据的时候调用
listView.setFootviewType(FOOTVIEW_TYPE.NOMOR)
列表底部显示改为 回到顶部 用户点击后自动跳到第一行!

嗯,很好!很强大!必须就顶一个!欢迎拍砖!


你可能感兴趣的:(android,ListView,动态加载)