野人学Android第二弹——自定义ListView第一课

在APP界,不管是微信还是微博,都会使用到ListView这一基本的控件,所以学好ListView有多么重要。所谓“工欲善其事必先利其器”,要想开发更加优质的APP,那么就需要花点精力研究下ListView啦。本节课,我想探讨下ListView的自定义原理,以不变应万变。

-----------------------------分割线--------------------------------

在讲自定义的ListView之前,先简单回顾下ListView的实现原理,即ListView(列表控件)——Adapter(适配器)——Data(数据)。关键的地方就是Adapter,系统自带的Adpater有ArrayAdapter和SimpleAdapter,前者只可以展示简单的文字,后者能展示图片和文字。但是,系统自带的Adapter无法满足个性化需求,那就需要进行自定义。其实,自定义的ListView,最主要的还是对Adapter进行自定义。新建adapter,继承BaseAdapter,代码如下:

<span style="font-size:14px;">import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class NewAdapter extends BaseAdapter {

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		return null;
	}

}
</span>

继承BaseAdapter之后,需要重新定义四个方法,如上所示。其中最重要的是getView(int position,View convertView, ViewGroup parent),一开始我是完全看不懂这个方法里面的参数,后来找到一些源码的注释,才算有些理解。我一开始查看了BaseAdapter的源码,发现没有这个方法,然后发现BaseAdapter继承了ListAdapter,不过也没有在ListAdapter中发现这个方法,直到追查到Adapter,才发现以下的一些注释。


翻译:获取展示数据集中特定位置的数据的视图。你可以手动地创建一个视图,或者从一个XML布局文件中填充出来。当视图被填充后,父视图(GridView, ListView...)会应用默认的参数,除非你使用inflate(int, ViewGroup, boolean)来绑定特定的根视图和避免依附根。

参数 position 在我们想要视图的适配器数据集中的项目位置。

参数 convertView 指的是可以重复使用的旧的视图。注意:在使用前,你应该检查这个视图不为空以及类型合适。如果无法将视图转换成能显示正确数据的视图,那么这个方法可以创建一个新的视图。复杂的列表能指定他们视图类型的数字,所以视图能一直保持正确的类型。

参数 parent 视图最终会依附的父类

返回 绑定特定位置数据的视图


翻译得不是很完美,请见谅。在此,我再重复强调一点,当屏幕进行滑动的时候,ListView中会有一部分View消失掉,但是convertView会重复使用这个实例化的view,那么就增加了效率。所以convertView可以理解为重复使用的view,那么在初始化的时候,就需要对convertView进行判断,如果为空,那么就要赋值,如果不为空,那么就直接调用。除此之外,还要引入一个新的概念ViewHolder,一个自定义的控件集合类。代码如下:

<span style="font-size:14px;">@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder holder = null;
		if(convertView == null){
			//mInflater的类型是LayoutInflater,item_listview是item的xml文件
			convertView = mInflater.inflate(R.layout.item_listview, parent,false);
			holder = new ViewHolder();//实例化一个控件类
			holder.mName = (TextView) convertView.findViewById(R.id.textName);//根据id创建一个view,然后赋值给viewHolder类
			holder.mPhone = (TextView) convertView.findViewById(R.id.textPhone);
			holder.mAge = (TextView) convertView.findViewById(R.id.textAge);
			
			convertView.setTag(holder);//最后将实例化的holder赋值给convertView
		}else{
			holder = (ViewHolder) convertView.getTag();//如果convertView不为空,那么就获取holder
		}
		Bean bean = mDatas.get(position);//bean是一个数据类,包括name,phone和age三个属性
		holder.mName.setText(bean.getName());
		holder.mPhone.setText(bean.getPhone());
		holder.mAge.setText(bean.getAge()+"");
		return convertView;//返回convertView
	}
	private class ViewHolder{
		TextView mName;
		TextView mPhone;
		TextView mAge;
		
	}</span>

getView()的基本逻辑是,首先判断convertView是否为空,如果为空,那么就实例化视图,然后赋值给ViewHolder类,最后利用setTag()赋值给convertView;如果不为空,那么就是之前已经赋值过了,可以直接用getTag()获取holder。当获取holder之后,就可以开始赋值了。最后返回convertView就可以了。而ViewHolder就是一个控件类。有了这个思路,就可以编写自定义的Adapter了。

关于R.layout.item_listview.xml和ListView与适配器的绑定,我就不写了。祝大家好运~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值