项目需求讨论-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

求别乱喷,求点赞。哈哈。。。。。。

相关文章
相关标签/搜索