VLayout的使用

先來(lái)看看下面這個(gè)頁(yè)面的實(shí)現(xiàn):

device-2018-02-27-102830.png

按照我們平時(shí)的習(xí)慣凯旋,最后的布局文件如下:

<ScrollView>
    <LinearLayout>
        <ImageView>  <頂部圖片>
        <LinearLayout><View/><TextView/><LinearLayout>   <我的服務(wù)標(biāo)題欄>
        <GridView />   <我的服務(wù)功能塊>

        <LinearLayout><View/><TextView/><LinearLayout>   <我的功能標(biāo)題欄>
        <GridView />   <我的功能功能塊>
    <LinearLayout>
<ScrollView/>

可以看出,布局很復(fù)雜。如果在想加一個(gè)“我的售后”模塊呢至非,就需要找到相應(yīng)的布局代碼钠署,在相應(yīng)的位置加上布局代碼,這樣很麻煩荒椭,不利于擴(kuò)展...

下面我們來(lái)看看阿里巴巴開(kāi)源的vlayout
對(duì)于上面的頁(yè)面我們來(lái)使用VLayout來(lái)進(jìn)行實(shí)現(xiàn)谐鼎,我們先看看布局代碼:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rv_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.v7.widget.RecyclerView>

整個(gè)頁(yè)面的布局,就只有一個(gè)RecyclerView控件趣惠,簡(jiǎn)單吧...

它的功能實(shí)現(xiàn)狸棍,有兩種寫法,首先我們來(lái)看看比較通用點(diǎn)的實(shí)現(xiàn)味悄,它的思路大概就是:為每個(gè)模塊建立一個(gè)Adapter草戈,然后將這些Adapter放入一個(gè)總集合中,最后把這個(gè)集合設(shè)置給RecyclerView侍瑟。

上面的頁(yè)面唐片,我們可以分為三個(gè)模塊:頂部圖片,標(biāo)題欄涨颜,功能塊费韭。這樣對(duì)應(yīng)的也就有三個(gè)Adapter,依次如下:

//頂部圖片BannerAdapter

public class BannerAdapter extends DelegateAdapter.Adapter<BannerAdapter.ViewHolder> {
    private Context context;
    private List<Integer> urls;
    private LayoutHelper layoutHelper;

    public BannerAdapter(Context context, List<Integer> urls, LayoutHelper layoutHelper){
        this.context = context;
        this.urls = urls;
        this.layoutHelper = layoutHelper;
    }

    @Override
    public LayoutHelper onCreateLayoutHelper() {
        return layoutHelper;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_banner, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Glide.with(context).load(urls.get(position)).into(holder.imageView);
    }

    @Override
    public int getItemCount() {
        return urls.size();
    }


    public class ViewHolder extends RecyclerView.ViewHolder{
        ImageView imageView;

        public ViewHolder(View itemView) {
            super(itemView);

            imageView = itemView.findViewById(R.id.iv_banner);
        }
    }
}
//標(biāo)題欄DividerAdapter

public class DividerAdapter extends DelegateAdapter.Adapter<DividerAdapter.DividerViewHolder> {
    private Context context;
    private List<String> itemBeanList;
    private LayoutHelper layoutHelper;

    public DividerAdapter(Context context, List<String> itemBeanList, LayoutHelper layoutHelper){
        this.context = context;
        this.itemBeanList = itemBeanList;
        this.layoutHelper = layoutHelper;
    }

    @Override
    public LayoutHelper onCreateLayoutHelper() {
        return layoutHelper;
    }

    @Override
    public DividerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new DividerViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_divider, parent, false));
    }

    @Override
    public void onBindViewHolder(DividerViewHolder holder, int position) {
        holder.tvName.setText(itemBeanList.get(position));
    }

    @Override
    public int getItemCount() {
        return itemBeanList.size();
    }


    public class DividerViewHolder extends RecyclerView.ViewHolder{
        private TextView tvName;

        public DividerViewHolder(View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tv_name);
        }
    }
}
//功能塊ContentAdapter 

public class ContentAdapter extends DelegateAdapter.Adapter<ContentAdapter.ContentViewHolder> {
    private Context context;
    private List<ItemBean> itemBeanList;
    private LayoutHelper layoutHelper;

    public ContentAdapter(Context context, List<ItemBean> itemBeanList, LayoutHelper layoutHelper){
        this.context = context;
        this.itemBeanList = itemBeanList;
        this.layoutHelper = layoutHelper;
    }

    @Override
    public LayoutHelper onCreateLayoutHelper() {
        return layoutHelper;
    }

    @Override
    public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ContentViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_content, parent, false));
    }

    @Override
    public void onBindViewHolder(ContentViewHolder holder, int position) {
        Glide.with(context).load(Integer.parseInt(itemBeanList.get(position).getImgUrl())).into(holder.icon);
        holder.tvName.setText(itemBeanList.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return itemBeanList.size();
    }


    public class ContentViewHolder extends RecyclerView.ViewHolder{
        private ImageView icon;
        private TextView tvName;

        public ContentViewHolder(View itemView) {
            super(itemView);

            icon = itemView.findViewById(R.id.iv_icon);
            tvName = itemView.findViewById(R.id.tv_name);
        }
    }
}

這樣各個(gè)模塊的適配器就寫完了,下面就是使用了...

VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);//建立我們的委托LayoutManger
        rvLayout.setLayoutManager(layoutManager);

        /**
         * 目前的LayoutHelper有以下幾種:
         *
         * LinearLayoutHelper: 線性布局
         * GridLayoutHelper: Grid布局庭瑰, 支持橫向的colspan
         * FixLayoutHelper: 固定布局星持,始終在屏幕固定位置顯示
         * ScrollFixLayoutHelper: 固定布局,但之后當(dāng)頁(yè)面滑動(dòng)到該圖片區(qū)域才顯示, 可以用來(lái)做返回頂部或其他書(shū)簽等
         * FloatLayoutHelper: 浮動(dòng)布局弹灭,可以固定顯示在屏幕上督暂,但用戶可以拖拽其位置
         * ColumnLayoutHelper: 欄格布局,都布局在一排鲤屡,可以配置不同列之間的寬度比值
         * SingleLayoutHelper: 通欄布局损痰,只會(huì)顯示一個(gè)組件View
         * OnePlusNLayoutHelper: 一拖N布局,可以配置1-5個(gè)子元素
         * StickyLayoutHelper: stikcy布局酒来, 可以配置吸頂或者吸底
         * StaggeredGridLayoutHelper: 瀑布流布局,可配置間隔高度/寬度
         */

        //頂部圖片
        SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
        bannerLayoutHelper.setItemCount(1);//設(shè)置子條目個(gè)數(shù)
        List<Integer> imgList = new ArrayList<>();
        imgList.add(R.drawable.banner);
        adapters.add(new BannerAdapter(this, imgList, bannerLayoutHelper));

        //第一個(gè)標(biāo)題欄:我的服務(wù)
        LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
        serverLayoutHelper.setItemCount(1);
        List<String> list = new ArrayList<>();
        list.add("我的服務(wù)");
        adapters.add(new DividerAdapter(this, list, serverLayoutHelper));

        //我的服務(wù)肪凛,功能塊
        GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
        serverGridLayoutHelper.setAutoExpand(false);//是否自動(dòng)擴(kuò)展
        serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});//設(shè)置權(quán)重
        serverGridLayoutHelper.setItemCount(6);
        adapters.add(new ContentAdapter(this, serverList, serverGridLayoutHelper));

       //第二個(gè)標(biāo)題欄:我的功能
        LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
        functionLayoutHelper.setItemCount(1);
        layoutHelperList.add(functionLayoutHelper);
        List<String> list1 = new ArrayList<>();
        list1.add("我的功能");
        adapters.add(new DividerAdapter(this, list1, functionLayoutHelper));

       //我的功能堰汉,功能塊
        GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
        functionGridLayoutHelper.setAutoExpand(false);
        functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
        functionGridLayoutHelper.setItemCount(6);
        adapters.add(new ContentAdapter(this, functionList, functionGridLayoutHelper));

        DelegateAdapter adapter1 = new DelegateAdapter(layoutManager, false);
        adapter1.setAdapters(adapters);//添加不同的子Adapter.
        rvLayout.setAdapter(adapter1);

這樣就完成了,對(duì)上面頁(yè)面的實(shí)現(xiàn)伟墙。

如果我想新加一個(gè)功能塊翘鸭,我們只需要針對(duì)這個(gè)功能塊,新建一個(gè)Adapter戳葵,在將其加入集合adapters中就可以了就乓,不需要在去更改原來(lái)的代碼了....
我們?cè)趤?lái)看看另一種寫法,它的大概思路就是:為每個(gè)模塊設(shè)置一個(gè)LayoutHelper,然后將其放入LayoutHelper集合中生蚁,在將此集合設(shè)置給VirtualLayoutManager,最后在Adapter中進(jìn)行具體的處理噩翠。具體代碼如下:
        VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
        rvLayout.setLayoutManager(layoutManager);
        getData();//獲取數(shù)據(jù)
        /**
         * 目前的LayoutHelper有以下幾種:

         * LinearLayoutHelper: 線性布局
         * GridLayoutHelper: Grid布局, 支持橫向的colspan
         * FixLayoutHelper: 固定布局邦投,始終在屏幕固定位置顯示
         * ScrollFixLayoutHelper: 固定布局伤锚,但之后當(dāng)頁(yè)面滑動(dòng)到該圖片區(qū)域才顯示, 可以用來(lái)做返回頂部或其他書(shū)簽等
         * FloatLayoutHelper: 浮動(dòng)布局,可以固定顯示在屏幕上志衣,但用戶可以拖拽其位置
         * ColumnLayoutHelper: 欄格布局屯援,都布局在一排,可以配置不同列之間的寬度比值
         * SingleLayoutHelper: 通欄布局念脯,只會(huì)顯示一個(gè)組件View
         * OnePlusNLayoutHelper: 一拖N布局狞洋,可以配置1-5個(gè)子元素
         * StickyLayoutHelper: stikcy布局, 可以配置吸頂或者吸底
         * StaggeredGridLayoutHelper: 瀑布流布局绿店,可配置間隔高度/寬度
         */
        List<LayoutHelper> layoutHelperList = new ArrayList<>();

        //頂部圖片
        SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
        bannerLayoutHelper.setItemCount(1);
        layoutHelperList.add(bannerLayoutHelper);

        //我的服務(wù)標(biāo)題欄
        LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
        serverLayoutHelper.setItemCount(1);
        layoutHelperList.add(serverLayoutHelper);

        //我的服務(wù)
        GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
        serverGridLayoutHelper.setAutoExpand(false);
        serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});
        serverGridLayoutHelper.setItemCount(6);
        layoutHelperList.add(serverGridLayoutHelper);

        //我的功能標(biāo)題欄
        LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
        functionLayoutHelper.setItemCount(1);
        layoutHelperList.add(functionLayoutHelper);

        //我的功能
        GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
        functionGridLayoutHelper.setAutoExpand(false);
        functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
        functionGridLayoutHelper.setItemCount(6);
        layoutHelperList.add(functionGridLayoutHelper);

        layoutManager.setLayoutHelpers(layoutHelperList);//設(shè)置LayoutHelper集合

        VLayoutAdapter adapter = new VLayoutAdapter(layoutManager, this, serverList, functionList);
        rvLayout.setAdapter(adapter);
//整體Adapter
public class VLayoutAdapter extends VirtualLayoutAdapter {
    private int serverNum;
    private int functionNum;
    private Context context;
    private List<ItemBean> serverList = new ArrayList<>();
    private List<ItemBean> functionList = new ArrayList<>();

    private final int FLAG_BANNER = 1;//banner
    private final int FLAG_DIVIDER = 2;//標(biāo)題欄
    private final int FLAG_CONTENT = 3;//功能塊

    public VLayoutAdapter(@NonNull VirtualLayoutManager layoutManager, Context context, List<ItemBean> serverList, List<ItemBean> functionList) {
        super(layoutManager);
        this.serverList = serverList;
        this.functionList = functionList;
        this.context = context;

        serverNum = serverList.size();
        functionNum = functionList.size();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType){
            case FLAG_BANNER:
                return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_banner, parent, false));
            case FLAG_DIVIDER:
                return new DividerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_divider, parent, false));
            case FLAG_CONTENT:
                return new ContentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_content, parent, false));
            default:
                return null;
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof BannerViewHolder){
            Glide.with(context).load(R.drawable.banner).into(((BannerViewHolder) holder).banner);
        }else if (holder instanceof DividerViewHolder){
            if (position == 1){
                ((DividerViewHolder) holder).tvName.setText("我的服務(wù)");
                ((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#F9C025"));
            }else{
                ((DividerViewHolder) holder).tvName.setText("我的功能");
                ((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#35A7FF"));
            }
        }else if (holder instanceof ContentViewHolder){
            if (position > 1 && position < 2+serverNum){
                ((ContentViewHolder) holder).tvName.setText(serverList.get(position-2).getName());
                Glide.with(context).load(Integer.parseInt(serverList.get(position-2).getImgUrl())).into(((ContentViewHolder) holder).icon);
            }else if (position > 2+serverNum){
                ((ContentViewHolder) holder).tvName.setText(functionList.get(position-(2+serverNum+1)).getName());
                Glide.with(context).load(Integer.parseInt(functionList.get(position-(2+serverNum+1)).getImgUrl())).into(((ContentViewHolder) holder).icon);
            }
        }
    }

    @Override
    public int getItemCount() {//返回總條目數(shù)
        int totalCount = 0;
        List<LayoutHelper> helpers = getLayoutHelpers();//獲取全部的LayoutHelper
        if (helpers == null ) {
            return 0;
        }
        for (int i = 0; i < helpers.size(); i++) {
            totalCount += helpers.get(i).getItemCount();//獲取LayoutHelper中的子條目數(shù)
        }
        return totalCount;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0){
            return FLAG_BANNER;
        }else if (position == 1 || position == (2+serverNum)){
            return FLAG_DIVIDER;
        }else {
            return FLAG_CONTENT;
        }
    }

    public class BannerViewHolder extends RecyclerView.ViewHolder{
        private ImageView banner;

        public BannerViewHolder(View itemView) {
            super(itemView);
            banner = itemView.findViewById(R.id.iv_banner);
        }
    }

    public class DividerViewHolder extends RecyclerView.ViewHolder{
        private TextView tvName;

        public DividerViewHolder(View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tv_name);
        }
    }

    public class ContentViewHolder extends RecyclerView.ViewHolder{
        private ImageView icon;
        private TextView tvName;

        public ContentViewHolder(View itemView) {
            super(itemView);

            icon = itemView.findViewById(R.id.iv_icon);
            tvName = itemView.findViewById(R.id.tv_name);
        }
    }
}

從上面的adapter代碼中可以看出吉懊,如果我新加一個(gè)功能模塊,那么就得新加一個(gè)標(biāo)識(shí)類型惯吕,在onBindViewHolder中就得多加一條if..else判斷惕它;這樣的話新增功能越多,判定就加的越多废登,對(duì)于維護(hù)不利淹魄;所以這種寫法雖然簡(jiǎn)單,但是不適合功能模塊比較多的頁(yè)面堡距。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甲锡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子羽戒,更是在濱河造成了極大的恐慌缤沦,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件易稠,死亡現(xiàn)場(chǎng)離奇詭異缸废,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驶社,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門企量,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人亡电,你說(shuō)我怎么就攤上這事届巩。” “怎么了份乒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵恕汇,是天一觀的道長(zhǎng)腕唧。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瘾英,這世上最難降的妖魔是什么枣接? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮方咆,結(jié)果婚禮上月腋,老公的妹妹穿的比我還像新娘。我一直安慰自己瓣赂,他們只是感情好榆骚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著煌集,像睡著了一般妓肢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上苫纤,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天碉钠,我揣著相機(jī)與錄音,去河邊找鬼卷拘。 笑死喊废,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的栗弟。 我是一名探鬼主播污筷,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乍赫!你這毒婦竟也來(lái)了瓣蛀?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雷厂,失蹤者是張志新(化名)和其女友劉穎惋增,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體改鲫,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诈皿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了像棘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纫塌。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖讲弄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情依痊,我是刑警寧澤避除,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布怎披,位于F島的核電站,受9級(jí)特大地震影響瓶摆,放射性物質(zhì)發(fā)生泄漏凉逛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一群井、第九天 我趴在偏房一處隱蔽的房頂上張望状飞。 院中可真熱鬧,春花似錦书斜、人聲如沸诬辈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)焙糟。三九已至,卻和暖如春样屠,著一層夾襖步出監(jiān)牢的瞬間穿撮,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工痪欲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悦穿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓业踢,卻偏偏與公主長(zhǎng)得像栗柒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陨亡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容