ListView通用泛型適配器
還記得我們之前說(shuō)的ListView嗎,(這個(gè)難用的控件-。+)我們?cè)谟盟耐瑫r(shí)也用到了一個(gè)叫做適配器Adapter的東西。一般我們用一個(gè)類繼承BaseAdapter,來(lái)進(jìn)行數(shù)據(jù)和控件的適配。
但是我們每一種適配器都只是為了適配一種數(shù)據(jù)源和一種布局,如果用到的少還好,如果要用到十幾種,我們是不是要寫十幾個(gè)適配器呢?這個(gè)想法真的是太蠢了!
有一種適配器寫法,可以做到一個(gè)適配器與多種類型數(shù)據(jù)和布局進(jìn)行適配,這個(gè)東西叫做通用適配器(因?yàn)樗怯玫椒盒蛯?shí)現(xiàn)的,我稱他為泛型適配器),今天我們來(lái)看一下這種適配器的寫法:
在寫之前呢,我們首先回憶一下之前所用到的BaseAdapter適配器:
我們通過(guò)繼承BaseAdapter,實(shí)現(xiàn)了他的四個(gè)方法:getCount,getPosition,getItem,和getView。其中最難寫的就是getView了,然后我們還對(duì)他進(jìn)行了優(yōu)化:通過(guò)寫一個(gè)叫做ViewHolder的類,在里面放入對(duì)應(yīng)的控件。
現(xiàn)在我們首先來(lái)說(shuō)一下通用適配器和一般的適配器的區(qū)別和相同點(diǎn):

接下來(lái)我們正式來(lái)看一下通用適配器的寫法:
1.先創(chuàng)建好我們今天需要的控件、源數(shù)據(jù)以及Bean類。
控件只有一個(gè)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方法模擬了一個(gè)假數(shù)據(jù)
private void beans() {
list = new ArrayList<>();
for (int i = 0; i < 16; i += 4) {
list.add(new Student("同學(xué)" + i, "男", 15 + i, R.drawable.a, true));
list.add(new Student("同學(xué)" + (i + 1), "男", 15 + i, R.drawable.b, false));
list.add(new Student("同學(xué)" + (i + 2), "男", 15 + i, R.drawable.c, false));
list.add(new Student("同學(xué)" + (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.創(chuàng)建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.我們說(shuō)通用適配器傳入布局id和源數(shù)據(jù),所以我們定義這兩個(gè)量接收傳入的數(shù)據(jù)。
private List<Student> list;
private int mLayRes;
public MyBaseAdapter(List<Student> list, int mLayRes) {
this.list= list;
this.mLayRes = mLayRes;
}
4.重寫我們的前三個(gè)方法
前三個(gè)方法應(yīng)該算是比較簡(jiǎn)單的了,
@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;
}
第一個(gè)一個(gè)簡(jiǎn)單的判斷,返回list的大小。第二個(gè)跟第三個(gè)和以前適配器一樣,只是getItem的返回值寫成了泛型。
5.寫Viewholder類,這個(gè)是很麻煩的,我們先創(chuàng)建出來(lái)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;
}
東西有點(diǎn)多,我們順著邏輯慢慢看:
1)首先是通過(guò)單例來(lái)實(shí)現(xiàn),所以我們需要一個(gè)私有化構(gòu)造方法,里面有三個(gè)參數(shù),分別是上下文,ViewGroup和布局id,這三個(gè)屬性是我們必須要用到的,我們傳入上下文獲取inflater,把布局id傳進(jìn)去,然后把holder傳入我們的itemView中。
這一步我們應(yīng)該比較熟悉吧,我們以前是在getView中實(shí)現(xiàn)這一步的。
2)然后我們看下面的bind方法,他的參數(shù)有五個(gè)。其實(shí)有三個(gè)參數(shù)我們很熟悉,就是我們getView中的三個(gè)參數(shù)。在這基礎(chǔ)上我們又添加了兩個(gè)參數(shù),布局id和上下文。
然后為了優(yōu)化我們先判斷當(dāng)前的convertView是否為空,如果為空就新建一個(gè)Viewholder,讓convertView在私有構(gòu)造器中加載;如果不為空,直接通過(guò)getTag拿到。
注意我們要對(duì)holder中的兩個(gè)參數(shù)進(jìn)行修改,一個(gè)是itemView,一個(gè)是position。因?yàn)槲覀儍?yōu)化過(guò)后,如果convertView不為空,他里面是有之前的數(shù)據(jù)的,其他的幾個(gè)屬性我們不用管,但是這兩個(gè)還是儲(chǔ)存著上一個(gè)的內(nèi)容。我們需要讓他重新指向當(dāng)前的convertView和position,給大家畫一張圖就很明白了:

索引什么的畫的可能不準(zhǔn)確,但是主要就是這么個(gè)意思,大家領(lǐng)會(huì)精神哈。
最后返回holder。
3)我們還需要返回我們加載完成的convertView,
public View getItemView() {
return itemView;
}
現(xiàn)在我們Viewholder基本框架寫完了,我們暫時(shí)不管他了,去寫getView。
6.重寫方法getView:
我們剛才說(shuō)了,在adapter中寫一個(gè)抽象方法,然后通過(guò)回調(diào)方法,實(shí)現(xiàn)多類型適配,也就是說(shuō)這個(gè)抽象方法是寫我們給具體控件添加數(shù)據(jù)的,我們?cè)谶@里面?zhèn)鬟f兩個(gè)參數(shù),一個(gè)是我們的Viewholder,另一個(gè)是對(duì)應(yīng)位置的數(shù)據(jù),類型為泛型。
public abstract void bindView(ViewHolder holder,T obj);
因?yàn)槲覀兂霈F(xiàn)了抽象方法,所以我們的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();
}
現(xiàn)在我們的適配器已經(jīng)完成百分之九十了,還差一點(diǎn),我們需要寫幾個(gè)輔助方法,為了方便我們等會(huì)進(jìn)行適配。
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中寫一個(gè)getView方法,通過(guò)控件id來(lái)獲取指定控件。
2.TextView控件輸入數(shù)據(jù)
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.復(fù)選框輸入選定狀態(tài)
public ViewHolder setCheckable(int id,boolean checkable){
View view = getView(id);
if(view instanceof View){
((CheckBox)view).setChecked(checkable);
}
return this;
}
好啦,先在我們的適配器完全寫完了,我們來(lái)看一下效果吧。
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);
}

雖然效果有點(diǎn)丑,但是功能我們實(shí)現(xiàn)了哈哈,大家如果不信可以在創(chuàng)建一個(gè)新的bean類和新的layout布局試驗(yàn)一下,同樣可以。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- Android ListView和Adapter數(shù)據(jù)適配器的簡(jiǎn)單介紹
- 詳解xamarin Android 實(shí)現(xiàn)ListView萬(wàn)能適配器
- Android ListView適配器(Adapter)優(yōu)化方法詳解
- Android ListView萬(wàn)能適配器實(shí)例代碼
- Android巧用XListView實(shí)現(xiàn)萬(wàn)能下拉刷新控件
- android使用flutter的ListView實(shí)現(xiàn)滾動(dòng)列表的示例代碼
- Android自定義控件ListView下拉刷新的代碼
- MVPXlistView展示上拉下拉效果
- Android通過(guò)代碼控制ListView上下滾動(dòng)的方法
- Android解決ScrollView下嵌套ListView和GridView中內(nèi)容顯示不全的問(wèn)題
相關(guān)文章
新浪微博第三方登錄界面上下拉伸圖片之第三方開(kāi)源PullToZoomListViewEx(二)
這篇文章主要介紹了新浪微博第三方登錄界面上下拉伸圖片之第三方開(kāi)源PullToZoomListViewEx(二) 的相關(guān)資料,需要的朋友可以參考下2015-12-12
Android App中實(shí)現(xiàn)圖片異步加載的實(shí)例分享
這篇文章主要介紹了Android App中實(shí)現(xiàn)圖片異步加載的實(shí)例分享,這樣GridView在加載大量圖片時(shí)便可以延時(shí)分布顯示,需要的朋友可以參考下2016-04-04
Handler實(shí)現(xiàn)線程之間的通信下載文件動(dòng)態(tài)更新進(jìn)度條
每一個(gè)線程對(duì)應(yīng)一個(gè)消息隊(duì)列MessageQueue,實(shí)現(xiàn)線程之間的通信,可通過(guò)Handler對(duì)象將數(shù)據(jù)裝進(jìn)Message中,再將消息加入消息隊(duì)列,而后線程會(huì)依次處理消息隊(duì)列中的消息。這篇文章主要介紹了Handler實(shí)現(xiàn)線程之間的通信下載文件動(dòng)態(tài)更新進(jìn)度條,需要的朋友可以參考下2017-08-08
Android 推送原理(Android Push Notification)詳解
這篇文章主要介紹了Android 推送原理(Android Push Notification)詳解的相關(guān)資料,這里對(duì)Android 推送的原理做了簡(jiǎn)單的介紹,需要的朋友可以參考下2016-11-11
Android實(shí)現(xiàn)長(zhǎng)按圖片保存至相冊(cè)功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)長(zhǎng)按圖片保存至相冊(cè)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Presenting?Streams?in?Flutter小技巧
這篇文章主要為大家介紹了Presenting?Streams?in?Flutter小技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Kotlin示例講解標(biāo)準(zhǔn)函數(shù)with與run和apply的使用
Kotlin的標(biāo)準(zhǔn)函數(shù)是指 Standard.kt 文件中定義的函數(shù),任何Kotlin代碼都可以自由地調(diào)用所有的標(biāo)準(zhǔn)函數(shù)。文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-08-08
詳解Retrofit Interceptor(攔截器) 攔截請(qǐng)求并做相關(guān)處理
本篇文章主要介紹了詳解Retrofit Interceptor(攔截器) 攔截請(qǐng)求并做相關(guān)處理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04

