一個ListView根據標識加載不同佈局,很簡單的例子,就是聊天界面,你說話在右邊好友在左邊怎麼實現呢.

我不是一個標題黨,我也是自己遇到了這個問題,想給後面的人一個快速解決的方法

  1. 我最開始的方法是通過將兩個佈局寫在一個佈局文件裏, 通過顯示和隱藏控件,來實現這樣的效果,這樣看起來重用的控件利用率高了呀,→_→,但是有時候控制的好揪心,難道就不能加載兩個佈局麼,我來說一下嘗試的方法

  2. 加載兩個佈局,肯定沒問題,你只需要傳入一個標識,我在getView()方法里根據position拿到相應的數據,拿到標識位,就可以去加載不同的佈局了,這肯定可以,

但是,這樣就不能用ViewHolder了因爲第一次,你去使用ViewHolder的時候,判斷convertView是否爲空,第二次就是不爲空了,從ViewHolder中取控件賦值了,這是關鍵點,你可以用兩個ViewHolder存儲,關鍵還是convertView的複用,


其實你只是沒清楚convertView複用,我們有開發經驗的朋友應該都知道ListView的緩存機制

ListView顯示的view從我們重寫的getView方法創建,並且一共創建的個數是一屏顯示的個數比方說我們手機上一屏能顯示3個item,那麼ListView剛開始顯示的時候就創建了3個ListView的item,而當我們向上滾動ListView的時候第一個item不可見,下面的第4個item並沒有重新創建而實際上覆用的是第一個item。這樣設計的目的就是爲我們節省了很大的內存開銷。

在ListView的父類AbsListView中,有一個變量RecycleBin mRecycler
用來存儲某一顯示項佈局對應的視圖。實際存儲在 ArrayList[] 中,
該數組的長度爲getViewTypeCount的返回值。

RecycleBin 是AbsListView的一個內部類。 當ListView執行setAdapter方法時,mRecycler會重置,getViewTypeCount方法會被調用。當ListView要顯示某一項時,getItemViewType方法被調用,根據返回值在mRecycler搜索得到緩存的視圖(重點在這裏!!!我們只需要在getItemViewType中做手腳即可)

這也是爲什麼getViewTypeCount返回值要比定義的視圖類型常量值大的原因,否則會導致數組越界異常。然後調用getView方法,緩存的視圖被傳遞給getView方法的convertView形參 , 當傳遞進來的convertView形參爲null的話,需要根據該項的視圖類型,初始化佈局。最後給顯示項填充數據。

我們滑動到讓第4個item顯示出來之前,首先會執行getItemViewType這個方法判斷該行item的類型,然後再從緩存池中查看是否有該類型item的緩存給我們用,有的話就直接拿過來,沒有就創建

getViewTypeCount()//告訴ListView我共有多少種item,
getItemViewType()//方法告訴ListView每行該顯示哪種item,

並且該方法中返回的type類型必須爲整數且不能大於getViewTypeCount返回的數。

//這是適配器的默認實現方法 也就只有一種佈局類型
public int getItemViewType(int position){return 0;}
public int getViewTypeCount() {return 1;  }

關鍵代碼

//在適配器定義兩個類型常量 和一個類型總數量
public static final int TYPE_1= 0;
public static final int TYPE_2= 1;
public static final int TYPE_COUNT = 2;

//類型的數值不能大於TYPE_COUNT 
//類型的數值不能大於TYPE_COUNT 
//類型的數值不能大於TYPE_COUNT 
//這個是最重要的代碼 ,ListView根據這個返回值判斷是不是有緩存視圖
//即getView()方法的 convertView是不是爲null
public int getItemViewType(int position) {
        if ("0".equals(datas.get(position).geType())) {
            return TYPE_1;// 類型1 
        } else if ("1".equals(datas.get(position).getType())) {
            return TYPE_2;// 類型2
        } else {
            return 100;
        }
    }
    public int getViewTypeCount() {
        return TYPE_COUNT;
    }
//補充一點>>>>>>> 我有一個疑問,就是他用getItemType()去判斷有木有這個緩存視圖的是怎麼實現的,最開始又沒有這兩個類型的視圖,怎麼去判斷!
//實際上,重寫兩個方法之後,getView方法中
//會自動的將原本只有一屏數據list集合中
//再加上TYPE_COUNT個數的視圖,這裏是再多存放了兩個視圖,用於之後的複用,
public View getView(int position, View convertView, ViewGroup parent) {
    //兩個視圖
    View view_1 = null;
    View view_2 = null;
    Person  p = datas.get(position); //獲取相應的數據

    currentType = getItemViewType(position);//重點代碼

    if (currentType == TYPE_1) {

        ViewHolder_1 holder_1 = null; //view_1的holder
        if (convertView == null) {
            holder_1 = new ViewHolder_1();

            view_1 = LayoutInflater.from(mContext).
            inflate(R.layout.view_1, null); //加載視圖View_1

            //對holder_1 初始化

            view_1.setTag(holder_1); //緩存holder_1
            convertView = view_1; //將convertView賦值
        } else {
            holder_1= (ViewHolder_1) convertView.getTag();
        }
        //各種對ViewHolder的控件進行賦值

    } else if (currentType == TYPE_2) {
        ViewHolder_2 holer_2 = null;
        if (convertView == null) {
            holer_2 = new ViewHolder_2 ();

            view_2 = LayoutInflater.from(mContext).
            inflate(R.layout.view_2, null); //加載視圖2
            //對holer_2 初始化
            view_2.setTag(holer_2);
            convertView = view_2; //給convertView賦值
        } else {
            holer_2= (ViewHolder_2) convertView.getTag();
        }

        //各種對ViewHolder_2的控件進行賦值
    }
    return convertView; //返回視圖
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章