Android 動態加載 ListView 實現

首先講原理: java

ListView 能夠設置一個滾動監聽器 android

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 ide

/**
 * 下拉自動加載的 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()
列表就展現新數據了! this

此外我這裏面還封裝了一個神奇的功能是設置 FootView 狀態:
這裏有四種狀態: spa

public enum FOOTVIEW_TYPE {
		/** 加載中 */
		LOADING, 
		/** 沒有更多了,返回頂部 */
		NOMOR, 
		/** 加載失敗重試 */
		RETRY,
		/**無*/
		NONE
	}
在加載下一頁失敗的時候,調用
listView.setFootviewType(FOOTVIEW_TYPE.RETRY)
列表底部顯示改成,加載失敗,點擊重試,用戶點擊以後,會再次回調你的 load() 方法


同理
當你沒有更多數據的時候調用
listView.setFootviewType(FOOTVIEW_TYPE.NOMOR)
列表底部顯示改成 回到頂部 用戶點擊後自動跳到第一行!
code

嗯,很好!很強大!必須就頂一個!歡迎拍磚! rem

相關文章
相關標籤/搜索