您的位置:首页 > 移动开发 > Android开发

Android 动态加载 ListView 实现

2013-07-04 23:31 459 查看
首先讲原理:

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)
列表底部显示改为 回到顶部 用户点击后自动跳到第一行!

嗯,很好!很强大!必须就顶一个!欢迎拍砖!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息