ListView通用泛型适配器
还记得我们之前说的listview吗,(这个难用的控件-。+)我们在用他的同时也用到了一个叫做适配器adapter的东西。一般我们用一个类继承baseadapter,来进行数据和控件的适配。
但是我们每一种适配器都只是为了适配一种数据源和一种布局,如果用到的少还好,如果要用到十几种,我们是不是要写十几个适配器呢?这个想法真的是太蠢了!
有一种适配器写法,可以做到一个适配器与多种类型数据和布局进行适配,这个东西叫做通用适配器(因为他是用到泛型实现的,我称他为泛型适配器),今天我们来看一下这种适配器的写法:
在写之前呢,我们首先回忆一下之前所用到的baseadapter适配器:
我们通过继承baseadapter,实现了他的四个方法:getcount,getposition,getitem,和getview。其中最难写的就是getview了,然后我们还对他进行了优化:通过写一个叫做viewholder的类,在里面放入对应的控件。
现在我们首先来说一下通用适配器和一般的适配器的区别和相同点:
接下来我们正式来看一下通用适配器的写法:
1.先创建好我们今天需要的控件、源数据以及bean类。
控件只有一个listview
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns: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方法模拟了一个假数据
private void beans() { list = new arraylist<>(); for (int i = 0; i < 16; i += 4) { list.add(new student("同学" + i, "男", 15 + i, r.drawable.a, true)); list.add(new student("同学" + (i + 1), "男", 15 + i, r.drawable.b, false)); list.add(new student("同学" + (i + 2), "男", 15 + i, r.drawable.c, false)); list.add(new student("同学" + (i + 3), "男", 15 + i, r.drawable.d, true)); } }
这是bean类
package zy.pers.homework_20.bean; public class student { private string name; private string sex; private int age; private int imgid; private boolean isover; public student(string name, string sex, int age, int imgid,boolean isover) { this.name = name; this.sex = sex; this.age = age; this.imgid = imgid; this.isover = isover; } public string getname() { return name; } public void setname(string name) { this.name = name; } public string getsex() { return sex; } public void setsex(string sex) { this.sex = sex; } public int getage() { return age; } public void setage(int age) { this.age = age; } public int getimgid() { return imgid; } public void setimgid(int imgid) { this.imgid = imgid; } @override public string tostring() { return "student{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", age=" + age + ", imgid=" + imgid + '}'; } public boolean isover() { return isover; } public void setover(boolean over) { isover = over; } }
2.创建mybaseadapter继承baseadapter
public class mybaseadapter<t> extends baseadapter { @override public int getcount() { return 0; } @override public object getitem(int position) { return null; } @override public long getitemid(int position) { return 0; } @override public view getview(int position, view convertview, viewgroup parent) { return null; } }
3.我们说通用适配器传入布局id和源数据,所以我们定义这两个量接收传入的数据。
private list<student> list; private int mlayres; public mybaseadapter(list<student> list, int mlayres) { this.list= list; this.mlayres = mlayres; }
4.重写我们的前三个方法
前三个方法应该算是比较简单的了,
@override public int getcount() { return list != null ? list.size() : 0; } @override public t getitem(int position) { return list.get(position); } @override public long getitemid(int position) { return position; }
第一个一个简单的判断,返回list的大小。第二个跟第三个和以前适配器一样,只是getitem的返回值写成了泛型。
5.写viewholder类,这个是很麻烦的,我们先创建出来viewholder,之后的方法我们一步一步添加。
public static class viewholder { private sparsearray<view> mviews = new sparsearray<>(); private context mcontext; private int position; private int layres; private view itemview;
private viewholder(context context, viewgroup parent, int layres) { this.mcontext = context; this.layres= layres; this.itemview = layoutinflater.from(context).inflate(layres, parent, false); this.itemview.settag(this); }
public static viewholder bind(int position, view convertview, viewgroup parent, int layres, context context) { viewholder holder; if (convertview == null) { holder = new viewholder(context, parent, layres); } else { holder = (viewholder) convertview.gettag(); holder.itemview = convertview; } holder.position = position; return holder; }
东西有点多,我们顺着逻辑慢慢看:
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,
public view getitemview() { return itemview; }
现在我们viewholder基本框架写完了,我们暂时不管他了,去写getview。
6.重写方法getview:
我们刚才说了,在adapter中写一个抽象方法,然后通过回调方法,实现多类型适配,也就是说这个抽象方法是写我们给具体控件添加数据的,我们在这里面传递两个参数,一个是我们的viewholder,另一个是对应位置的数据,类型为泛型。
public abstract void bindview(viewholder holder,t obj);
因为我们出现了抽象方法,所以我们的mybaseadapter需要变成抽象类,
public abstract class mybaseadapter<t> extends baseadapter {
这是我们的getview
@override public view getview(int position, view convertview, viewgroup parent) { viewholder holder = viewholder.bind(position,convertview,parent,mlayres,parent.getcontext()); bindview(holder,list.get(position)); return holder.getitemview(); }
现在我们的适配器已经完成百分之九十了,还差一点,我们需要写几个辅助方法,为了方便我们等会进行适配。
1.获取指定控件
public <t extends view> t getview(int id){ t t = (t) mviews.get(id); if(t == null){ t = itemview.findviewbyid(id); mviews.put(id,t); } return t; }
在viewholder中写一个getview方法,通过控件id来获取指定控件。
2.textview控件输入数据
public viewholder settext(int id,charsequence text){ view view = getview(id); if(view instanceof view){ ((textview)view).settext(text); } return this; }
3.imageview输入图片
public viewholder setimg(int id,int resid){ view view = getview(id); if(view instanceof view){ ((imageview)view).setimageresource(resid); }else view.setbackgroundresource(resid); return this; }
4.复选框输入选定状态
public viewholder setcheckable(int id,boolean checkable){ view view = getview(id); if(view instanceof view){ ((checkbox)view).setchecked(checkable); } return this; }
好啦,先在我们的适配器完全写完了,我们来看一下效果吧。
private void inittools() { listview mlv = (listview) findviewbyid(r.id.mlv); adapter = new mybaseadapter<student>(list,r.layout.item_one) { @override public void bindview(viewholder holder, student obj) { 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); }
虽然效果有点丑,但是功能我们实现了哈哈,大家如果不信可以在创建一个新的bean类和新的layout布局试验一下,同样可以。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接
上一篇: 协程执行顺序测试备份
下一篇: Hotspot VM 重要参数选项