項目需求討論-Vlayout來快速構建及擴展複雜界面

你們好,今天又帶來了項目中具體遇到的需求。作一個首界面,該首界面有不少功能塊,同時這些功能塊是動態的,由於登陸的人的權限的不一樣,會顯示不一樣的功能塊,由於功能模塊的數量不必定,因此當功能塊多的時候,整個界面是能夠上下滑動的。其實相似有點像淘寶的首界面。以下圖所示。javascript

界面


首先我說的不是最優的。可能有更好的解決方式。我這裏也只是嘗試了新的方式而已。

我先說下我最剛開始想到的最傳統的想法:

1.首先由於功能塊多的時候,須要界面可以滾動,因此我想到最外面用的ScrollView,而後ScrollView中包含了一個豎向排布的LienarLayout。
而後在放入一個ImageView顯示這個頂部圖片:
java

而後須要二個橫向的LinearLayout,用來顯示這個大的分類標題:android

而後再放入二個GridView顯示功能模塊:git

OK。我發現個人首界面寫好了以後:github

<ScrollView>
    <LinearLayout>
        <ImageView>  <頂部圖片>
        <LinearLayout><View/><TextView/><LinearLayout>   <個人服務標題欄>
        <GridView />   <個人服務功能塊>

        <LinearLayout><View/><TextView/><LinearLayout>   <個人功能標題欄>
        <GridView />   <個人功能功能塊>
    <LinearLayout>
<ScrollView/>複製代碼

1.佈局的內容很是之多。維護很不方便
2.定製化功能差了不少,若是我下次想在《個人服務》和《個人功能》大功能分類中,再多加一個《個人售後》,又的去佈局中查找相應的位置,而後去去添加新的佈局代碼,或者是我想刪除模塊功能了,我還得去佈局中找出來,而後去刪除它。反正就是很麻煩。
3.當前這個界面還算簡單的,畢竟功能塊都是以相似九宮格的形式呈現,若是哪天多了個《個人售後》,而後這個《個人售後》不是以這種九宮格的形式呈現,整個界面中有各類各樣的布句呈現,管理會變的十分麻煩。算法


有沒有什麼好的辦法呢。

上面說到過。咱們的界面有沒有像淘寶的首界面,各類布句雜糅在一塊兒,而後又能夠上下滾動,沒錯,那我就模仿淘寶的首頁同樣寫個不就好了麼。框架

這時候個人思路就變了:整個界面就使用一個RecycleView來完成。

而後裏面的不一樣佈局方式使用不一樣的LayoutManager不就能夠了麼。固然由於前面講了咱們能夠模仿淘寶的首頁來寫,那咱們固然是使用阿里巴巴開源的vlayoutide

這時候介紹一下咱們的主角:vlayout函數

vlayout is a powerfull LayoutManager extension for RecyclerView, it provides a group of layouts for RecyclerView. Make it able to handle a complicate situation when grid, list and other layouts in the same recyclerview.佈局

咱們能夠看到,vlayout是一個強大的RecycleView的LayoutManager,它能夠幫我在RecycleView中呈現多種佈局方式。


正式起航:

首先,vlayout的基本使用方法,其餘大神寫的不少也很好。我也不會浪費時間再寫一遍:

請看這篇,基本就可以對Vlayout有所瞭解及使用了:

重要的事情說三遍!!!你們必定要看一遍再使用。

Android開源庫V - Layout:淘寶、天貓都在用的UI框架,趕忙用起來吧!
Android開源庫V - Layout:淘寶、天貓都在用的UI框架,趕忙用起來吧!
Android開源庫V - Layout:淘寶、天貓都在用的UI框架,趕忙用起來吧!

咱們回頭再來看咱們上面的具體的項目需求:

(我會先用VLayout實現一種簡單的處理。而後再實現更加通用的處理!必定要看完最後的通用處理哦!)

簡單處理:

咱們首先整個activity的佈局變爲了:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/work_recycleview" android:background="@android:color/white" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" > </android.support.v7.widget.RecyclerView>複製代碼

是否是變的乾淨簡潔了!!!

而後咱們要使用Vlayout來設置咱們RecycleView中的各類佈局。

RecycleView workRecycleview = (RecycleView)findViewById(R.id.work_recycleview);
//創建咱們的委託LayoutManger
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
workRecycleview.setLayoutManager(layoutManager);
//經過這個layoutManager來管理一系列的LayoutHelper
//因此咱們先創建一個List來存放等會要用到的LayoutHelper.
List<LayoutHelper> helperList = new LinkedList<>();
//1.
//由於第一個底部圖片就這一項,因此咱們就直接使用SingleLayoutHelper
SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
bannerLayoutHelper.setItemCount(1);
helperList.add(bannerLayoutHelper);

//2.
//由於大標題欄是一個橫向的LinearLayout,因此使用LinearLayoutHelper
LinearLayoutHelper personTitleHelper = new LinearLayoutHelper();
personTitleHelper.setItemCount(1);
helperList.add(personTitleHelper);

//3.
//由於功能塊目前是九宮格,因此使用的是GridLayoutHelper
GridLayoutHelper personGridHelper = new GridLayoutHelper(3);
personGridHelper.setAutoExpand(false);
personGridHelper.setWeights(new float[]{33, 33, 33});
//設置登陸時候獲取到的該用戶權限下顯示的功能數量。
personGridHelper.setItemCount(mPersonFunctions.size());
helperList.add(personGridHelper);

//4.
//同2界面
LinearLayoutHelper companyTitleHelper = new LinearLayoutHelper();
companyTitleHelper.setItemCount(1);
helperList.add(companyTitleHelper);

//5.
//同3界面
GridLayoutHelper companyGridHelper = new GridLayoutHelper(3);
companyGridHelper.setWeights(new float[]{33, 33, 33});
companyGridHelper.setAutoExpand(false);
//設置登陸時候獲取到的該用戶權限下顯示的功能數量。
companyGridHelper.setItemCount(mCompanyFunctions.size());
helperList.add(companyGridHelper);複製代碼

若是咱們須要增長新的佈局控制。咱們只須要添加新的LayoutHelper,按順序添加到咱們的helperList中便可。

目前的LayoutHelper有如下幾種:

  • LinearLayoutHelper: 線性佈局
  • GridLayoutHelper: Grid佈局, 支持橫向的colspan
  • FixLayoutHelper: 固定佈局,始終在屏幕固定位置顯示
  • ScrollFixLayoutHelper: 固定佈局,但以後當頁面滑動到該圖片區域才顯示, 能夠用來作返回頂部或其餘書籤等
  • FloatLayoutHelper: 浮動佈局,能夠固定顯示在屏幕上,但用戶能夠拖拽其位置
  • ColumnLayoutHelper: 欄格佈局,都佈局在一排,能夠配置不一樣列之間的寬度比值
  • SingleLayoutHelper: 通欄佈局,只會顯示一個組件View
  • OnePlusNLayoutHelper: 一拖N佈局,能夠配置1-5個子元素
  • StickyLayoutHelper: stikcy佈局, 能夠配置吸頂或者吸底
  • StaggeredGridLayoutHelper: 瀑布流佈局,可配置間隔高度/寬度

既然用到RecycleView ,那怎麼能夠沒有Adapter呢,上面的準備工做作了一部分後,咱們開始寫咱們的Adapter。

咱們這裏選擇繼承了VirtualLayoutAdapter:
咱們在構造函數中傳入咱們二個九宮格功能塊對應的List進來。

public class WorkAdapter extends VirtualLayoutAdapter {
    int oneFuncs, twoFuncs;//
    public List<FunctionBean> oneFunctions;
    public List<FunctionBean> twoFunctions;

    public static final int BANNER_VIEW_TYPE = 0;
    public static final int DIVIDER_VIEW_TYPE = 1;
    public static final int FUN_VIEW_TYPE = 2;

    public WorkAdapter(@NonNull VirtualLayoutManager layoutManager, List<FunctionBean> oneFunctions, List<FunctionBean> twoFunctions,funcItemOnClickListener listener) {
        super(layoutManager);
        this.oneFunctions = oneFunctions;
        this.twoFunctions = twoFunctions;
        this.listener = listener;

        oneFuncs = oneFunctions.size();
        twoFuncs = twoFunctions.size();
    }


}複製代碼

咱們來分別看Adapter中每一個方法具體的複寫:
1.

@Override
public int getItemCount() {
    int totalCount = 0;
    List<LayoutHelper> helpers = getLayoutHelpers();
    if (helpers == null) {
        return 0;
    }
    for (int i = 0; i < helpers.size(); i++) {
        totalCount += helpers.get(i).getItemCount();
    }
    return totalCount;
}複製代碼

咱們能夠看到在getItemCount()方法中,咱們經過遍歷了LayoutHelper,分別取每一個LayoutHelper中咱們剛設置的個數。而後加起來,做爲整個RecycleView 的個數。

2.

@Override
public int getItemViewType(int position) {
    if (position == 0) {
        return BANNER_VIEW_TYPE;
    } else if (position == 1 || position == (2 + oneFuncs)) {
        return DIVIDER_VIEW_TYPE;
    } else {
        return FUN_VIEW_TYPE;
    }
}複製代碼

咱們能夠看到。咱們在getItemViewType方法中確定position的值,返回不一樣的type,這樣等會在onCreateViewHolder方法中就能夠返回不一樣的ViewHolder了。

3.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    switch (viewType) {
        case BANNER_VIEW_TYPE:
            return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_work_banner, parent, false));
        case DIVIDER_VIEW_TYPE:
            return new DividerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_work_divider, parent, false));
        case FUN_VIEW_TYPE:
            return new FuncViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_work_func, parent, false));
        default:
            return null;
    }
}複製代碼

4.

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof DividerViewHolder) {
        if (position == 1) {
            ((DividerViewHolder) holder).dividerTitle.setText("個人服務");
            ((DividerViewHolder) holder).colorView.setBackgroundColor(Color.parseColor("#F9C025"));
        } else {
            ((DividerViewHolder) holder).dividerTitle.setText("個人功能");
            ((DividerViewHolder) holder).colorView.setBackgroundColor(Color.parseColor("#35A7FF"));
        }
    } else if (holder instanceof FuncViewHolder) {
        if(position > 1 && position < 2+ oneFuncs){
          ...
          ...
          ...

        }else if(position > 2+ oneFuncs){
          ...
          ...
          ...
        }
    }
}複製代碼

就這樣咱們就具體的實現了多個佈局的設置,並且當你要再加一個新的也很方便。可是也許你這時候會發現,若是咱們的佈局很長,有不少九宮格,或者真的像淘寶同樣,這個界面有各類功能塊。那咱們剛寫的

@Override
public int getItemViewType(int position) {
    if (position == 0) {
        return BANNER_VIEW_TYPE;
    } else if (position == 1 || position == (2 + oneFuncs)) {
        return DIVIDER_VIEW_TYPE;
    } else {
        return FUN_VIEW_TYPE;
    }
}複製代碼

這裏你判斷的position就會不少。你可能就要有不少的if-else 來控制返回不一樣的type.

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof DividerViewHolder) {
        if (position == 1) {
            ((DividerViewHolder) holder).dividerTitle.setText("個人服務");
            ((DividerViewHolder) holder).colorView.setBackgroundColor(Color.parseColor("#F9C025"));
        } else {
            ((DividerViewHolder) holder).dividerTitle.setText("個人功能");
            ((DividerViewHolder) holder).colorView.setBackgroundColor(Color.parseColor("#35A7FF"));
        }
    } else if (holder instanceof FuncViewHolder) {
        if(position > 1 && position < 2+ oneFuncs){
          ...
          ...
          ...

        }else if(position > 2+ oneFuncs){
          ...
          ...
          ...
        }
    }
}複製代碼

而後在onBindViewHolder方法裏面也要有不少的if-else,到後面維護又會變的很麻煩,因此這樣寫相對簡單,適合模塊很少的狀況。



複雜的而且更通用的實現:

咱們前面是把不少LayoutHelper加入到了Adapter中,而後RecycleView直接設置該Adapter,
咱們此次就不這麼作了。並且中間多設置一步,就是先每一個LayoutHelper設置一個Adapter,成爲<子的Adapter>,而後把這些Adapter再統一放入到一個<總的Adapter>中,再把這個<總的Adapter>賦值給RecycleView便可。

由於這樣在<總的Adapter>中,對於每一個Helper就能夠知道個數,而且ViewHolder等賦值都被分配到了那些<子的Adapter>中處理了。咱們不用再if-else的寫不少狀況了。

咱們直接來看這個<總的Adapter> 是如何實現的:

(不過我不會徹底很仔細的講解,代碼我也不會貼所有,就貼一些主要的地方,講主要的部分。)

1.

public class DelegateAdapter extends VirtualLayoutAdapter<RecyclerView.ViewHolder> {

    private int mTotal = 0;
    private int mIndex = 0;
    private SparseArray<Adapter> mItemTypeAry = new SparseArray<>();
    @NonNull
    private final List<Pair<AdapterDataObserver, Adapter>> mAdapters = new ArrayList<>();
    private final SparseArray<Pair<AdapterDataObserver, Adapter>> mIndexAry = new SparseArray<>();

}複製代碼

咱們先定義了幾個參數,

mIndex用來等於標記各個加入的<子的Adapter>的序號

一個用來存<子的Adapter>的Map(別問我爲何Map類型裏面只填了一個Adapter,不是Key-Value? 能夠補下SparseArray和ArrayMap的知識了,Android中用來替換HashMap的類。)

一個存放了Pair<AdapterDataObserver, Adapter>的List集合(Pair若是也不知道,也能夠去補充下,就簡單理解爲一個有二個屬性的對象,第一個屬性是AdapterDataObserver,第二個是Adapter)

一個存放了Pair<AdapterDataObserver, Adapter>的Map集合。

2.
那咱們知道確定要有個方法把這些子的Adapter給加進來:

public void setAdapters(@Nullable List<Adapter> adapters) {
    clear();//把相關的參數都從新置空,這裏不寫出來了。

    if (adapters == null) {
        adapters = Collections.emptyList();
    }

    List<LayoutHelper> helpers = new LinkedList<>();

    mTotal = 0;

    Pair<AdapterDataObserver, Adapter> pair;
    for (Adapter adapter : adapters) {
        // every adapter has an unique index id

        //自定義類AdapterDataObserver ,繼承於RecyclerView.AdapterDataObserver
        AdapterDataObserver observer = new AdapterDataObserver(mTotal, mIndex++);
        adapter.registerAdapterDataObserver(observer);

       //子的Adapter中自定義的方法:onCreateLayoutHelper(),用來返回子的Adapter中的LayoutHelper
        LayoutHelper helper = adapter.onCreateLayoutHelper();

        //並且這些子的Adapter中的LayoutHelper的個數,就是這些子的Adapter的個數
        helper.setItemCount(adapter.getItemCount());

        //總數爲每一個LayoutHelper的個數之和,也就是每一個子的Adapter的個數之和
        mTotal += helper.getItemCount();
        helpers.add(helper);


        pair = Pair.create(observer, adapter);
        //這裏的mIndexAry存放了以加入的順序mIndex爲Key的Pair<AdapterObserver,Adapter>
        mIndexAry.put(observer.mIndex, pair);
        //同時mAdapters的List集合中也存放了Pair<AdapterObserver,Adapter>
        mAdapters.add(pair);
    }

    super.setLayoutHelpers(helpers);
}複製代碼

咱們看下AdapterDataObser的部分代碼:

protected class AdapterDataObserver extends RecyclerView.AdapterDataObserver {
    int mStartPosition;
    int mIndex = -1;

    public AdapterDataObserver(int startPosition, int index) {
        this.mStartPosition = startPosition;
        this.mIndex = index;
    }
}複製代碼

咱們能夠看到咱們剛在new每一個AdapterDataObser的時候傳入的構造函數參數是mTotal, mIndex++,這樣是否是正好每一個Adapter中的AdapterDataObserver中的mStartPosition參數就是你的這個Adapter在全部整個RecycleView中的開始的position值。而mIndex又說明了這個AdapterDataObserver是第幾個,也就是這個Adapter是全部的<子的Adapter>中的第幾個。

3.

@Override
public int getItemCount() {
    return mTotal;
}複製代碼

總數就是返回上面咱們的mTotal參數。

4.

@Override
public int getItemViewType(int position) {
    Pair<AdapterDataObserver, Adapter> p = findAdapterByPosition(position);
    if (p == null) {
        return RecyclerView.INVALID_TYPE;
    }

    int subItemType = p.second.getItemViewType(position - p.first.mStartPosition);

    if (subItemType < 0) {
        // negative integer, invalid, just return
        return subItemType;
    }

   if (mHasConsistItemType) {
    mItemTypeAry.put(subItemType, p.second);
    return subItemType;
    }

    int index = p.first.mIndex;

    return (int) getCantor(subItemType, index);
}複製代碼

咱們一步步來看這個比較關鍵的地方,咱們之因此不用咱們最剛開始第一次講的Vlayout使用的方法,就是由於咱們的LayoutHelper多了以後,在getItemViewType()方法中返回不一樣的ViewType須要不少if-else來處理。因此這裏咱們看他是如何自動處理的。

第一步:
Pair<AdapterDataObserver, Adapter> p = findAdapterByPosition(position);
咱們看findAdapterByPosition方法的具體實現:

@Nullable
public Pair<AdapterDataObserver, Adapter> findAdapterByPosition(int position) {

    //獲取咱們上面的mAdapter集合,裏面存的是Pair<AdapterObserver,Adapter>
    final int count = mAdapters.size();
    if (count == 0) {
        return null;
    }

    int s = 0, e = count - 1, m;
    Pair<AdapterDataObserver, Adapter> rs = null;

    // binary search range
    while (s <= e) {
        m = (s + e) / 2;
        rs = mAdapters.get(m);
        int endPosition = rs.first.mStartPosition + rs.second.getItemCount() - 1;

        if (rs.first.mStartPosition > position) {
            e = m - 1;
        } else if (endPosition < position) {
            s = m + 1;
        } else if (rs.first.mStartPosition <= position && endPosition >= position) {
            break;
        }

        rs = null;
    }

    return rs;
}複製代碼

經過這個方法的字面意思咱們不難理解:經過這個<總的Adapter>返回的item的position,來知道這個position是屬於咱們存了Adapter集合中的哪一個Adapter的。
先獲取咱們上面已經保存了各個Pair<AdapterObserver,Adapter>的mAdapters集合,而後判斷個數,爲0就直接返回了。不爲0,咱們就經過二分法查找的方式來進行查找。咱們前面已經在每一個AdapterDataObserver中存了相對於的Adapter的起始的Position,咱們只須要不停的判斷如今傳給這個方法的position是在(子的Adapter 的起始position) 與 (子的Adapter 的起始position + 子的Adapter的個數)之間,若是是,就說明是屬於這個Adapter,咱們就在mAdapters集合中取出相應的Pair<AdapterObserver,Adapter>

第二步:

int subItemType = p.second.getItemViewType(position - p.first.mStartPosition);

if (subItemType < 0) {
    // negative integer, invalid, just return
    return subItemType;
}

if (mHasConsistItemType) {
        mItemTypeAry.put(subItemType, p.second);
        return subItemType;
}

int index = p.first.mIndex;

return (int) getCantor(subItemType, index);複製代碼

這裏的(position - p.first.mStartPosition)其實就是這個<總的Adapter>的處於position的這一項,在這個<子的Adapter>裏面的具體的position值。最後經過這個<子的Adapter>的getItemViewType來獲得<子的Adapter>的ViewType。這樣就自動幫咱們判斷了在<總的Adapter>中的某個position值的Item的所屬的<子的Adapter>的ViewType了。而不用寫不少if-else來判斷了。

這裏又要分二種狀況,也就是一個boolean值mHasConsistItemType來控制:

在這個<總的Adapter>構造函數中傳入,它的做用是whether sub adapters itemTypes are consistent,就是咱們的全部的<子的Adapter>的itemType都是同樣的。由於若是你在<子的Adapter>中沒有覆寫getItemViewType方法的話,默認都是返回0,即:

public int getItemViewType(int position) {
        return 0;
}複製代碼

咱們也知道,RecycleView在運行的時候,執行順序是:

getItemViewType ->onCreateViewHolder ->
getItemViewType ->onCreateViewHolder ->
getItemViewType ->onCreateViewHolder ->...複製代碼

若是咱們的mHasConsistItemType設置爲true的話:
因此咱們若是全部的<子的Adapter>中的要用同一個viewType的話,好比這裏是0,咱們就在getItemViewType方法中執行mItemTypeAry.put(subItemType, p.second);,這樣當前的這個<子的Apdater>就存在了key爲0的集合中了,而後咱們在onCreateViewHolder方法中經過Adapter adapter = mItemTypeAry.get(viewType);取出來就好了,這時候由於viewType爲0,就正好取出來咱們剛存的Adapter,而後再進入下一次的getItemViewType的時候,就用新的adapter覆蓋了key爲0的value值,而後再拿到onCreateViewHolder方法裏面使用。

若是咱們的mHasConsistItemType設置爲false的話:
那這時候就用了另一種方法,首先,由於子的Adapter默認拿到的ViewType都是0,因此咱們用了要設置一個可逆算法,好比A方法和還原的B方法,A方法中咱們每次傳入viewType和另一個值(這裏選定了上面咱們拿到的Pair<AdapterDataObserver, Adapter>中的AdapterDataObserver的index值),由於每一個<子的Adapter>的index值不一樣,因此生成的ViewType也不一樣,而後咱們在onCreateViewHolder方法裏面,用還原的B方法,獲取到index值,而後經過這個index再找回<子的Adapter>,這時候咱們就能夠調用<子的Adapter>的onCreateViewHolder方法了。

A方法:

private static long getCantor(long k1, long k2) {
    return (k1 + k2) * (k1 + k2 + 1) / 2 + k2;
}複製代碼

B方法:(具體看onCreateViewHolder方法中)

// reverse Cantor Function
int w = (int) (Math.floor(Math.sqrt(8 * viewType + 1) - 1) / 2);
int t = (w * w + w) / 2;
int index = viewType - t;
int subItemType = w - index;複製代碼

5.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // reverse Cantor Function
    int w = (int) (Math.floor(Math.sqrt(8 * viewType + 1) - 1) / 2);
    int t = (w * w + w) / 2;

    int index = viewType - t;
    int subItemType = w - index;

    Adapter adapter  = findAdapterByIndex(index);
    if (adapter == null) {
        return null;
    }

    return adapter.onCreateViewHolder(parent, subItemType);
}複製代碼

6.

@SuppressWarnings("unchecked")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    Pair<AdapterDataObserver, Adapter> pair = findAdapterByPosition(position);
    if (pair == null) {
        return;
    }

    pair.second.onBindViewHolder(holder, position - pair.first.mStartPosition);
    pair.second.onBindViewHolderWithOffset(holder, position - pair.first.mStartPosition, position);
}複製代碼

findAdapterByPosition:(也是二分法查找,和上面的findAdapterByIndex方法同樣,不介紹了。)

@Nullable
public Pair<AdapterDataObserver, Adapter> findAdapterByPosition(int position) {
    final int count = mAdapters.size();
    if (count == 0) {
        return null;
    }

    int s = 0, e = count - 1, m;
    Pair<AdapterDataObserver, Adapter> rs = null;

    // binary search range
    while (s <= e) {
        m = (s + e) / 2;
        rs = mAdapters.get(m);
        int endPosition = rs.first.mStartPosition + rs.second.getItemCount() - 1;

        if (rs.first.mStartPosition > position) {
            e = m - 1;
        } else if (endPosition < position) {
            s = m + 1;
        } else if (rs.first.mStartPosition <= position && endPosition >= position) {
            break;
        }

        rs = null;
    }

    return rs;
}複製代碼

看了上面咱們發現了,最後咱們雖然給RecycleView賦值了一個<總的Adapter>,可是實際上的onCreateViewHolder方法和onBindViewHolder方法都是調用了每一個具體的<子的Adapter>的。

因此咱們最終在咱們的Activity中的使用

final DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager, true);
recyclerView.setAdapter(delegateAdapter);
List<DelegateAdapter.Adapter> adapters = new LinkedList<>();
adapters.add(XXXXX);//添加不一樣的子Adapter.
...
//好比這樣:
GridLayoutHelper layoutHelper;
layoutHelper = new GridLayoutHelper(4);
layoutHelper.setMargin(0, 10, 0, 10);
layoutHelper.setHGap(3);
layoutHelper.setAspectRatio(4f);
adapters.add(new ASubAdapter(this, layoutHelper, 8));
...
...
delegateAdapter.setAdapters(adapters);複製代碼

若是我想新加一個功能塊,只要新建一個針對這個功能塊的Adapter,而後添加到adapters集合中就能夠了。徹底不用修改原來的代碼。只須要在這個新加的功能塊的Adapter中處理便可。

具體的使用第二種方式的代碼及DelegateAdapter.java 的源碼 能夠在GitHub中自行觀看vlayout

求別亂噴,求點贊。哈哈。。。。。。

相關文章
相關標籤/搜索