ListView中怎么使用泛型适配器
这篇文章给大家介绍ListView中怎么使用泛型适配器,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
1.先创建好我们今天需要的控件、源数据以及Bean类。
控件只有一个ListView
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activities.MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/mlv"/> </LinearLayout>
beans方法模拟了一个假数据
privatevoidbeans(){ list=newArrayList<>(); for(inti=0;i<16;i+=4){ list.add(newStudent("同学"+i,"男",15+i,R.drawable.a,true)); list.add(newStudent("同学"+(i+1),"男",15+i,R.drawable.b,false)); list.add(newStudent("同学"+(i+2),"男",15+i,R.drawable.c,false)); list.add(newStudent("同学"+(i+3),"男",15+i,R.drawable.d,true)); } }
这是bean类
packagezy.pers.homework_20.bean; publicclassStudent{ privateStringname; privateStringsex; privateintage; privateintimgId; privatebooleanisOver; publicStudent(Stringname,Stringsex,intage,intimgId,booleanisOver){ this.name=name; this.sex=sex; this.age=age; this.imgId=imgId; this.isOver=isOver; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicStringgetSex(){ returnsex; } publicvoidsetSex(Stringsex){ this.sex=sex; } publicintgetAge(){ returnage; } publicvoidsetAge(intage){ this.age=age; } publicintgetImgId(){ returnimgId; } publicvoidsetImgId(intimgId){ this.imgId=imgId; } @Override publicStringtoString(){ return"Student{"+ "name='"+name+'\''+ ",sex='"+sex+'\''+ ",age="+age+ ",imgId="+imgId+ '}'; } publicbooleanisOver(){ returnisOver; } publicvoidsetOver(booleanover){ isOver=over; } }
2.创建MyBaseAdapter继承BaseAdapter
publicclassMyBaseAdapter<T>extendsBaseAdapter{ @Override publicintgetCount(){ return0; } @Override publicObjectgetItem(intposition){ returnnull; } @Override publiclonggetItemId(intposition){ return0; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ returnnull; } }
3.我们说通用适配器传入布局id和源数据,所以我们定义这两个量接收传入的数据。
privateList<Student>list; privateintmLayRes; publicMyBaseAdapter(List<Student>list,intmLayRes){ this.list=list; this.mLayRes=mLayRes; }
4.重写我们的前三个方法
前三个方法应该算是比较简单的了,
@Override publicintgetCount(){ returnlist!=null?list.size():0; } @Override publicTgetItem(intposition){ returnlist.get(position); } @Override publiclonggetItemId(intposition){ returnposition; }
第一个一个简单的判断,返回list的大小。第二个跟第三个和以前适配器一样,只是getItem的返回值写成了泛型。
5.写Viewholder类,这个是很麻烦的,我们先创建出来Viewholder,之后的方法我们一步一步添加。
publicstaticclassViewHolder{ privateSparseArray<View>mViews=newSparseArray<>(); privateContextmContext; privateintposition; privateintlayRes; privateViewitemView;
privateViewHolder(Contextcontext,ViewGroupparent,intlayRes){ this.mContext=context; this.layRes=layRes; this.itemView=LayoutInflater.from(context).inflate(layRes,parent,false); this.itemView.setTag(this); }
publicstaticViewHolderbind(intposition,ViewconvertView,ViewGroupparent,intlayRes,Contextcontext){ ViewHolderholder; if(convertView==null){ holder=newViewHolder(context,parent,layRes); }else{ holder=(ViewHolder)convertView.getTag(); holder.itemView=convertView; } holder.position=position; returnholder; }
东西有点多,我们顺着逻辑慢慢看:
1)首先是通过单例来实现,所以我们需要一个私有化构造方法,里面有三个参数,分别是上下文,ViewGroup和布局id,这三个属性是我们必须要用到的,我们传入上下文获取inflater,把布局id传进去,然后把holder传入我们的itemView中。
这一步我们应该比较熟悉吧,我们以前是在getView中实现这一步的。
2)然后我们看下面的bind方法,他的参数有五个。其实有三个参数我们很熟悉,就是我们getView中的三个参数。在这基础上我们又添加了两个参数,布局id和上下文。
然后为了优化我们先判断当前的convertView是否为空,如果为空就新建一个Viewholder,让convertView在私有构造器中加载;如果不为空,直接通过getTag拿到。
注意我们要对holder中的两个参数进行修改,一个是itemView,一个是position。因为我们优化过后,如果convertView不为空,他里面是有之前的数据的,其他的几个属性我们不用管,但是这两个还是储存着上一个的内容。我们需要让他重新指向当前的convertView和position,给大家画一张图就很明白了:
索引什么的画的可能不准确,但是主要就是这么个意思,大家领会精神哈。
最后返回holder。
3)我们还需要返回我们加载完成的convertView,
publicViewgetItemView(){ returnitemView; }
现在我们Viewholder基本框架写完了,我们暂时不管他了,去写getView。
6.重写方法getView:
我们刚才说了,在adapter中写一个抽象方法,然后通过回调方法,实现多类型适配,也就是说这个抽象方法是写我们给具体控件添加数据的,我们在这里面传递两个参数,一个是我们的Viewholder,另一个是对应位置的数据,类型为泛型。
publicabstractvoidbindView(ViewHolderholder,Tobj);
因为我们出现了抽象方法,所以我们的MyBaseAdapter需要变成抽象类,
publicabstractclassMyBaseAdapter<T>extendsBaseAdapter{
这是我们的getView
@Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ViewHolderholder=ViewHolder.bind(position,convertView,parent,mLayRes,parent.getContext()); bindView(holder,list.get(position)); returnholder.getItemView(); }
现在我们的适配器已经完成百分之九十了,还差一点,我们需要写几个辅助方法,为了方便我们等会进行适配。
1.获取指定控件
public<TextendsView>TgetView(intid){ Tt=(T)mViews.get(id); if(t==null){ t=itemView.findViewById(id); mViews.put(id,t); } returnt; }
在Viewholder中写一个getView方法,通过控件id来获取指定控件。
2.TextView控件输入数据
publicViewHoldersetText(intid,CharSequencetext){ Viewview=getView(id); if(viewinstanceofView){ ((TextView)view).setText(text); } returnthis; }
3.ImageView输入图片
publicViewHoldersetImg(intid,intresId){ Viewview=getView(id); if(viewinstanceofView){ ((ImageView)view).setImageResource(resId); }else view.setBackgroundResource(resId); returnthis; }
4.复选框输入选定状态
publicViewHoldersetCheckable(intid,booleancheckable){ Viewview=getView(id); if(viewinstanceofView){ ((CheckBox)view).setChecked(checkable); } returnthis; }
好啦,先在我们的适配器完全写完了,我们来看一下效果吧。
privatevoidinitTools(){ ListViewmLv=(ListView)findViewById(R.id.mlv); adapter=newMyBaseAdapter<Student>(list,R.layout.item_one){ @Override publicvoidbindView(ViewHolderholder,Studentobj){ holder.setText(R.id.name,obj.getName()) .setText(R.id.age,obj.getAge()+"") .setText(R.id.sex,obj.getSex()) .setImg(R.id.head,obj.getImgId()) .setCheckable(R.id.mc,obj.isOver()); } }; mLv.setAdapter(adapter); }
关于ListView中怎么使用泛型适配器就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。