Android ListView 加载空布局

        原创性声明:本文系作者原创,转载请附原文地址:http://blog.csdn.net/a774057695/article/details/48971429

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

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

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

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

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

我定义了四种状态:

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

切换状态的API:
  1.  ChangeToLoading() 
    显示等待状态视图
  2.  ChangeToRetry() 
    显示出错状态视图,请注意,何为出错请自行定义,例如加载网络数据超时时可以显示该布局,网络访问超时被定义为出错
  3.  ChangeToNormal()
    显示正常状态视图
  4.  ChangeToEmpty() 
    显示数据源为空状态视图,作者注:用于增强交互友好感,是否有实际需求请结合情况自行斟酌
设置非正常状态视图的函数原型:
  1.  void SetLoadingView(View v)
    或者 void SetLoadingView(int id) 
    设置等待状态的视图
  2.  void SetRetryView(View v)
    或者void SetRetryView(int id) 
    设置出错状态的视图
  3.  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







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值