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

来源:互联网 发布:星河战队3 知乎 编辑:程序博客网 时间:2024/05/19 20:39

在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 {@Overridepublic int getCount() {// TODO Auto-generated method stubreturn 0;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubreturn 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;">@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubViewHolder 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与适配器的绑定,我就不写了。祝大家好运~

0 0