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

Android ListView 加载空布局

2015-10-08 13:36 525 查看
        原创性声明:本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/48971429

        在上一篇文章中Android
ListView改变数据源,我们谈到了如何让ListView在数据源改变时处理的更加顺手,同时,我们遗留了一个问题,那就是没有数据时未能完成空布局的加载。

当时我试图从ListView入手,让listview加载一个空布局,然后发现,这比较难以实现,死磕代价太大,要把ListView大改。于是我想:为什么不做一个特殊的view,它具有不同的状态,不同状态时显示不同的布局呢。

        所以,我们的题目显得有点标题党,显示空布局(以及其他状态的布局)的并不是listview,而是它的父容器。

因为公司会将它作为一个项目,并需要实现更多的功能,所以这里我不方便开放源码。

       该部分我打包成了库,大家可以使用它,我将它上传到了csdn,下载地址,下面展示一下使用方法:

我定义了四种状态:

正常状态
意外状态
等待状态
数据为空状态(初始化时默认)
这四种状态会对应四种布局:
正常状态显示listview
其他三种状态使用用户自定义的布局,并且可以自定义其事件,需要注意的是,请在该布局最外层额外套一层布局容器,以保护布局。

切换状态的API:

 ChangeToLoading() 

显示等待状态视图
 ChangeToRetry() 

显示出错状态视图,请注意,何为出错请自行定义,例如加载网络数据超时时可以显示该布局,网络访问超时被定义为出错
 ChangeToNormal()

显示正常状态视图
 ChangeToEmpty() 

显示数据源为空状态视图,作者注:用于增强交互友好感,是否有实际需求请结合情况自行斟酌
设置非正常状态视图的函数原型:

 void SetLoadingView(View v)

或者 void SetLoadingView(int id) 

设置等待状态的视图
 void SetRetryView(View v)

或者void SetRetryView(int id) 

设置出错状态的视图
 void SetEmptyView(View v) 

或者void SetEmptyView(int id)

设置空数据时的视图
出于某些原因,在Activity的onDestroy中调用
Release()方法以实现某些功能组件的释放。

布局代码中添加组件:
<individual.leobert.superlistview.SuperListView
android:layout_width="match_parent"
android:layout_height="match_parent">
</individual.leobert.superlistview.SuperListView>


activity中声明实例并实例化:
private SuperListView mListView = null;
mListView =(SuperListView) findViewById(R.id.XXXXXXXXX);


listview的item布局可以自定义
listview的适配器请继承SuperListViewAdapter,并实现必要的方法,它看起来和继承baseadapter的类差不多,只是进行了更多的扩展
牵涉到数据变化的方法重写时请调用notifyDataSetChanged();这些是上一篇的内容了。
注意:设置适配器时,注意方法为:mListView.SetAdapter(mListAdapter);
这里给出demo中的一些文件:可以和上一篇对比阅读。
public class MainActivity extends Activity implements OnClickListener {

private SuperListView mListView = null;

private testAdapter mListAdapter = null;

private LinkedList<MyData> mData = null;

private Context mContext = null;

//==========\    测试数据   /===============================
/**
* 我们假定添加到第五条,位置应该是4,我们的位置和数据源一致,从0 开始,不考虑偏移值
* */
private final int testPosition = 4;

private MyData testData ;

private int testDataId = 0;
//==========\    测试数据定义结束     /==========================================

//=========\测试按钮 /=========================================
private Button tBAdd,tBAddAt,tBDeleteAt,tBDeleteAll;

private final String Tag = "MainActivity";

private Button Inview;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mContext = this;

BindView();

mData = new LinkedList<MyData>();
mListAdapter = new testAdapter(mData,mContext);
mListView.SetAdapter(mListAdapter);
//		testAddAll();
//
//		testReplaceAll();
Inview = (Button) findViewById(R.id.bt);
Inview.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
testAddAll();
}
});

}

private void testReplaceAll() {
GetData(3);
mListAdapter.ReplaceAll(mData);
}

private void testAddAll() {
GetData(5);
mListAdapter.AddAll(mData);
}

private void GetData(int count) {
mData = new LinkedList<MyData>();
for (int i = 0; i < count; i++) {
testData = new MyData(R.drawable.ic_launcher, "testAddAllData,id:"
+ i);
mData.add(testData);
}
}

private void BindView() {
mListView =(SuperListView) findViewById(R.id.main_list);

tBAdd = (Button) findViewById(R.id.bt_addAtLast);
tBAddAt = (Button) findViewById(R.id.bt_addAtPosition);
tBDeleteAt = (Button) findViewById(R.id.bt_deleteAtPosition);
tBDeleteAll = (Button) findViewById(R.id.bt_deleteAll);

tBAdd.setOnClickListener(this);
tBAddAt.setOnClickListener(this);
tBDeleteAll.setOnClickListener(this);
tBDeleteAt.setOnClickListener(this);

//		mListView.SetEmptyView(LayoutInflater.from(mContext).inflate(R.layout.nodata,null,true));
mListView.SetEmptyView(R.layout.nodata);
}

@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;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
boolean op = true;
StringBuffer msg  = new StringBuffer();
testData = new MyData(R.drawable.ic_launcher, "testData,id:"+(testDataId++));
boolean ret = false;
switch (v.getId()) {
case R.id.bt_addAtLast:
ret = mListAdapter.AddItem(testData);
msg.append("从尾部添加,成功了吗?").append(ret);
break;
case R.id.bt_addAtPosition:
ret = mListAdapter.AddItem(testPosition, testData);
msg.append("添加到第5条,成功了吗?").append(ret);
break;
case R.id.bt_deleteAtPosition:
ret = mListAdapter.DeleteItem(testPosition);
msg.append("删除第5条,成功了吗?").append(ret);
break;
case R.id.bt_deleteAll:
mListAdapter.Clear();
msg.append("全部清除");
break;
default:
op = false;
break;
}
mListView.ChangeToNormal();
if(op) {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
Log.i(Tag, msg.toString());
}
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mListView.Release();
}

}


适配器类:
public class testAdapter extends SuperListViewAdapter{

private Context mContext;

// 依据原楼主的代码,我们定义自己的数据类型,使用类来描述
private LinkedList<MyData> mLiData;

public testAdapter(LinkedList<MyData> mData, Context mContext) {
super(mContext);
this.mLiData = mData;
this.mContext = mContext;
}

private class ViewHolder {
ImageView mImageView;
TextView mTextView;
}

@Override
public int getCount() {
return mLiData.size();
}

/*
* 这里我返回数据源中的值。
*/
@Override
public Object getItem(int position) {
return mLiData.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
Log.i("adapter","getView");
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.listview_item, parent, false);
holder = new ViewHolder();
holder.mImageView = (ImageView) convertView
.findViewById(R.id.img_icon);
holder.mTextView = (TextView) convertView
.findViewById(R.id.txt_content);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.mImageView.setImageResource(mLiData.get(position).getImgId());
holder.mTextView.setText(mLiData.get(position).getContent());
return convertView;
}

//=======================================================================//
/*
* 以下是实现接口定义的方法
*
* 定义为Boolean 返回类型 是为了方便通知“前台”,成功了没有,
* 注意 我们的position按照数据来,从0开始,当然你看着自己需求指定偏移量也可以
*
* (⊙﹏⊙)b 我打着插入。。。想想还是改成了添加。。。感觉自己病了
*/
//=======================================================================//
@Override
public boolean AddItem(Object data) {
if (mLiData == null)
mLiData = new LinkedList<MyData>();
mLiData.add((MyData) data);
notifyDataSetChanged();
return true;
}

@Override
public boolean AddItem(int position , Object data) {
if (mLiData == null)
mLiData = new LinkedList<MyData>();
//注意超过了数据源的实际条目数时,需要的是添加到尾部,而不是直接添加,更不是在中间补充空值
//当然,你也可以认为必须朝该位置插入,不能满足时通知前台要求不被许可,不执行。 我的例子中就采用这样处理
if (position > getCount())
//			AddItem(data); //这里对应调整向朝尾部添加
return false;
else
mLiData.add(position,(MyData) data);
notifyDataSetChanged();
return true;
}

@Override
public boolean DeleteItem(int position) {
if (mLiData == null)
return false;
if (position >= getCount())
return false;
mLiData.remove(position);
notifyDataSetChanged();
return true;
}

public void Clear() {
if (mLiData == null)
mLiData = new LinkedList<MyData>();
mLiData.clear();

notifyDataSetChanged();
}

@SuppressWarnings("unchecked")
@Override
public void AddAll(Object datas) {
if (mLiData == null)
mLiData = new LinkedList<MyData>();
for(int i = 0;i<((LinkedList<MyData>) datas).size();i++) {
mLiData.add(((LinkedList<MyData>) datas).get(i));
}
notifyDataSetChanged();
}

@SuppressWarnings("unchecked")
@Override
public void ReplaceAll(Object datas) {
mLiData = new LinkedList<MyData>();
for(int i = 0;i<((LinkedList<MyData>) datas).size();i++) {
mLiData.add(((LinkedList<MyData>) datas).get(i));
}
notifyDataSetChanged();
}

}


至此,我们将上一篇中遗留的问题解决了。

本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/48971429
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: