VLayout全面解析

概述

最近看了下VLayout,它主要用在超複雜界面佈局,感覺確實比較好用,看了網上這篇文章,基本用法都已經寫到了,索性就轉載過來,方便後續複習。

github地址


VLayout簡介


vlayout全稱VirtualLayout,它是一個針對RecyclerView的LayoutManager擴展, 主要提供一整套佈局方案和佈局間的組件複用的問題。它通過定製化的LayoutManager,接管整個RecyclerView的佈局邏輯;LayoutManager管理了一系列LayoutHelper,LayoutHelper負責具體佈局邏輯實現的地方;每一個LayoutHelper負責頁面某一個範圍內的組件佈局;不同的LayoutHelper可以做不同的佈局邏輯,因此可以在一個RecyclerView頁面裏提供異構的佈局結構,這就能比系統自帶的LinearLayoutManager、GridLayoutManager等提供更加豐富的能力。同時支持擴展LayoutHelper來提供更多的佈局能力。

主要功能


  • 默認通用佈局實現,解耦所有的View和佈局之間的關係: Linear, Grid, 吸頂, 浮動, 固定位置等1:LinearLayoutHelper: 線性佈局2:GridLayoutHelper: Grid佈局, 支持橫向的colspan3:FixLayoutHelper: 固定佈局,始終在屏幕固定位置顯示4:ScrollFixLayoutHelper: 固定佈局,但之後當頁面滑動到該圖片區域才顯示, 可以用來做返回頂部或其他書籤等5:FloatLayoutHelper: 浮動佈局,可以固定顯示在屏幕上,但用戶可以拖拽其位置6:ColumnLayoutHelper: 欄格佈局,都佈局在一排,可以配置不同列之間的寬度比值7:SingleLayoutHelper: 通欄佈局,只會顯示一個組件View8:OnePlusNLayoutHelper: 一拖N佈局,可以配置1-5個子元素9:StickyLayoutHelper: stikcy佈局, 可以配置吸頂或者吸底10:StaggeredGridLayoutHelper: 瀑布流佈局,可配置間隔高度/寬度

  • 上述默認實現裏可以大致分爲兩類:一是非fix類型佈局,像線性、Grid、欄格等,它們的特點是佈局在整個頁面流裏,隨頁面滾動而滾動;另一類就是fix類型的佈局,它們的子節點往往不隨頁面滾動而滾動。

  • 所有除佈局外的組件複用,VirtualLayout將用來管理大的模塊佈局組合,擴展了RecyclerView,使得同一RecyclerView內的組件可以複用,減少View的創建和銷燬過程。

使用方法

版本請參考mvn repository上的最新版本(目前最新版本是1.0.3),最新的 aar 都會發布到 jcenter 和 MavenCentral 上,確保配置了這兩個倉庫源,然後引入aar依賴:

compile ('com.alibaba.android:vlayout:1.0.3@aar') {
    transitive = true
}

LayoutHelper功能介紹


margin, padding

Margin, padding就是外邊距、內邊距,概念與Android系統的margin, padding一樣,但也有不同的地方:

  • 它不是整個RecyclerView頁面的margin和padding,它是每一塊LayoutHelper所負責的區域的margin和padding。
  • 一個頁面裏可以有多個LayoutHelper,意味着不同LayoutHelper可以設置不同的margin和padding。
  • LayoutHelper的margin和padding與頁面RecyclerView的margin和padding可以共存。
  • 目前主要針對非fix類型的LayoutHelper實現了margin和padding,fix類型LayoutHelper內部沒有相對位置關係,不處理邊距。在這裏插入圖片描述
    對於LayoutHelper,調用
public void setPadding(int leftPadding, int topPadding, int rightPadding, int bottomPadding)public void setMargin(int leftMargin, int topMargin, int rightMargin, int bottomMargin)

bgColor, bgImg

背景顏色或者背景圖,這其實不是佈局屬性,但是由於在vlayout對視圖進行了直接佈局,不同區域的視圖的父節點都是RecyclerView,如果想要針對某一塊區域單獨繪製背景,就很難做到了。vlayout框架對此做了特殊處理,對於非fix、非float類型的LayoutHelper,支持配置背景色或背景圖。同樣目前主要針對非fix類型的LayoutHelper實現這個特性。在這裏插入圖片描述
使用背景色

public void setBgColor(int bgColor)

使用背景圖首先爲LayoutManager提供一個ImageView簡單工廠

this.mLayoutManager.setLayoutViewFactory(new LayoutViewFactory() {
            @Override
            public opinion generateLayoutView(@NonNull Context context) {
                return new XXImageView(context);
            }
        });

再爲LayoutHelper提設置圖片加載的Listener

baseHelper.setLayoutViewBindListener(new BindListener(imgUrl));
baseHelper.setLayoutViewUnBindListener(new UnbindListener(imgUrl));
​
​
private static class BindListener implements BaseLayoutHelper.LayoutViewBindListener {
        private String imgUrl;public BindListener(String imgUrl) {
            this.imgUrl = imgUrl;
        }@Override
        public void onBind(View layoutView, BaseLayoutHelper baseLayoutHelper) {
            //loading image
        }
    }private static class UnbindListener implements BaseLayoutHelper.LayoutViewUnBindListener {
    private String imgUrl;public UnbindListener(String imgUrl) {
        this. imgUrl = imgUrl;
    }@Override
    public void onUnbind(View layoutView, BaseLayoutHelper baseLayoutHelper) {
            //cancel loading image
    }
}

aspectRatio

爲了保證佈局過程中視圖的高度一致,我們設計了aspectRatio屬性,它是寬與高的比例,LayoutHelper裏有aspectRatio屬性,通過vlayout添加的視圖的LayoutParams也有aspectRatio屬性,後者的優先級比前者高,但含義不一樣。

  • LayoutHelper定義的aspectRatio,指的是一行視圖整體的寬度與高度之比,當然整體的寬度是減去了RecyclerView和對應的LayoutHelper的margin, padding。
  • 視圖的LayoutParams定義的aspectRatio,指的是在LayoutHelper計算出視圖寬度之後,用來確定視圖高度時使用的,它會覆蓋通過LayoutHelper的aspectRatio計算出來的視圖高度,因此具備更高優先級。

在這裏插入圖片描述
對於LayoutHelper,調用

public void setAspectRatio(float aspectRatio)

對於LayoutParams,調用

((VirutalLayoutManager.LayoutParams) layoutParams).mAspectRatio

在這裏插入圖片描述
對於LinearLayoutHelper,調用

public void setDividerHeight(int dividerHeight)

weights

ColumnLayoutHelper, GridLayoutHelper的屬性,它們都是提供網格狀的佈局能力,建議使用GridLayoutHelper,它的能力更加強大,參考下文介紹。默認情況下,每個網格中每一列的寬度是一樣的,通過weights屬性,可以指定讓每一列的寬度成比例分配,就像LinearLayout的weight屬性一樣。 weights屬性是一個float數組,每一項代表某一列佔父容器寬度的百分比,總和建議是100,否則佈局會超出容器寬度;如果佈局中有4列,那麼weights的長度也應該是4;長度大於4,多出的部分不參與寬度計算;如果小於4,不足的部分默認平分剩餘的空間。在這裏插入圖片描述
對於ColumnLayoutHelper, GridLayoutHelper,調用

public void setWeights(float[] weights)

vGap, hGap

GridLayoutHelper與StaggeredGridLayoutHelper都有這兩個屬性,分別控制視圖之間的垂直間距和水平間距。

在這裏插入圖片描述
對於GridLayoutHelper, StaggeredGridLayoutHelper,調用

public void setHGap(int hGap)public void setVGap(int vGap)

spanCount, spanSizeLookup

GridLayoutHelper的屬性,參考於系統的GridLayoutManager,spanCount表示網格的列數,默認情況下每一個視圖都佔用一個網格區域,但通過提供自定義的spanSizeLookUp,可以指定某個位置的視圖佔用多個網格區域。

在這裏插入圖片描述
使用spanCount調用

public void setSpanCount(int spanCount)

使用spanSizeLookup

public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup)

autoExpand

GridLayoutHelper的屬性,當一行裏視圖的個數少於spanCount值的時候,如果autoExpand爲true,視圖的總寬度會填滿可用區域;否則會在屏幕上留空白區域。

在這裏插入圖片描述
接口:

public void setAutoExpand(boolean isAutoExpand)

lane

StaggeredGridLayoutHelper中有這個屬性,與GridLayoutHelper裏的spanCount類似,控制瀑布流的列數。

接口:

public void setLane(int lane)

fixAreaAdjuster

fix類型的LayoutHelper,在可能需要設置一個相對父容器四個邊的偏移量,比如整個頁面裏有一個固定的標題欄添加在vlayout容器上,vlayout內部的fix類型視圖不希望與外部的標題有所重疊,那麼就可以設置一個fixAreaAdjuster來做偏移。在這裏插入圖片描述
接口:

public void setAdjuster(FixAreaAdjuster adjuster)

alignType, x, y

FixLayoutHelper, ScrollFixLayoutHelper, FloatLayoutHelper的屬性,表示吸邊時的基準位置,有四個取值,分別是TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT。x和y是相對這四個位置的偏移量,最終的偏移量還要受上述的fixAreaAdjuster影響。

  • TOP_LEFT:基準位置是左上角,x是視圖左邊相對父容器的左邊距偏移量,y是視圖頂邊相對父容器的上邊距偏移量;
  • TOP_RIGHT:基準位置是右上角,x是視圖右邊相對父容器的右邊距偏移量,y是視圖頂邊相對父容器的上邊距偏移量;
  • BOTTOM_LEFT:基準位置是左下角,x是視圖左邊相對父容器的左邊距偏移量,y是視圖底邊相對父容器的下邊距偏移量;
  • BOTTOM_RIGHT:基準位置是右下角,x是視圖右邊相對父容器的右邊距偏移量,y是視圖底邊相對父容器的下邊距偏移量;

在這裏插入圖片描述

設置基準調用

public void setAlignType(int alignType)

設置偏移量調用

public void setX(int x)public void setY(int y)

showType

ScrollFixLayoutHelper的屬性,取值有SHOW_ALWAYS, SHOW_ON_ENTER, SHOW_ON_LEAVE。

  • SHOW_ALWAYS:與FixLayoutHelper的行爲一致,固定在某個位置;
  • SHOW_ON_ENTER:默認不顯示視圖,當頁面滾動到這個視圖的位置的時候,才顯示;
  • SHOW_ON_LEAVE:默認不顯示視圖,當頁面滾出這個視圖的位置的時候顯示;

在這裏插入圖片描述
接口:

public void setShowType(int showType)

stickyStart, offset

StickyLayoutHelper的屬性,當視圖的位置在屏幕範圍內時,視圖會隨頁面滾動而滾動;當視圖的位置滑出屏幕時,StickyLayoutHelper會將視圖固定在頂部(stickyStart = true)或者底部(stickyStart = false),固定的位置支持設置偏移量offset。

在這裏插入圖片描述
接口:

public void setStickyStart(boolean stickyStart)public void setOffset(int offset)

實例演示


上面我們已經詳細介紹的各種LayoutHelper以及它的各種屬性,現在,我們通過demo來進行實例演示。

LinearLayoutHelper

我們activity只要進行一些簡單的配置就可以了:

  VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new DelegateRecyclerAdapter(this,new LinearLayoutHelper()));
        recycler.setAdapter(adapter);

對於adapter ,我們繼承DelegateAdapter來實現,代碼很簡單,如下:

 public LayoutHelper onCreateLayoutHelper() {
        return helper;
    }public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyViewholder(inflater.inflate(R.layout.item, parent, false));
    }public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ((MyViewholder) holder).text.setText(position + 1 + "");
    }public int getItemCount() {
        return 60;
    }public class MyViewholder extends RecyclerView.ViewHolder {private TextView text;public MyViewholder(View view) {
            super(view);
            text = (TextView) view.findViewById(R.id.text);
        }
    }

效果圖:

在這裏插入圖片描述

GridLayoutHelper

我們只要把LinearLayouthelper改成Gridlayouthelper就可以了:

  VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new DelegateRecyclerAdapter(this,new GridLayoutHelper(3)));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

StaggeredGridLayoutHelper

還是直接修改LayoutHelper就可以了:

     VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        //StaggeredGridLayoutHelper(int num,int gap)
        //num爲每行顯示數目,gap爲兩個item的邊距
        adapter.addAdapter(new StaggeredAdapter(this,new StaggeredGridLayoutHelper(3,20)));
        recycler.setAdapter(adapter);

爲了做成瀑布流的效果,我們對每個item進行一個隨機高度的設置:

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ViewGroup.LayoutParams layoutParams = ((MyViewholder) holder).text.getLayoutParams();
        layoutParams.height = 260 + position % 7 * 20;
        ((MyViewholder) holder).text.setLayoutParams(layoutParams);
        ((MyViewholder) holder).text.setText(position + 1 + "");
    }

效果圖:

在這裏插入圖片描述

FixLayoutHelper

對於fixlayout類型的,我們需要先後添加一次LinearLayoutHelper和FixLayoutHelper。

        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new DelegateRecyclerAdapter(this, new LinearLayoutHelper()));
        adapter.addAdapter(new ScrollFixAdapter(this, new FixLayoutHelper(FixLayoutHelper.BOTTOM_LEFT, 200, 200), recycler));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

ScrollFixLayoutHelper

同上,代碼是差不多的,不過官方所說的標籤,置頂等功能。並不能實現。官方demo也並沒有實現此功能。雖然我們可以通過點擊圖片來進行置頂。但是具體功能感覺和fixlayout無異。

ColumnLayoutHelper

代碼如下:

​
        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new DelegateRecyclerAdapter(this,new ColumnLayoutHelper()));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

SingleLayoutHelper

        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new DelegateRecyclerAdapter(this,new SingleLayoutHelper()));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

OnePlusNLayoutHelper

一拖N佈局

​
        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        OnePlusNLayoutHelper helper = new OnePlusNLayoutHelper(3);
        adapter.addAdapter(new OnePlusNRecyclerAdapter(this,helper));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

FloatLayoutHelper

​
        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        adapter.addAdapter(new FloatAdapter(this,new FloatLayoutHelper()));
        adapter.addAdapter(new DelegateRecyclerAdapter(this,new LinearLayoutHelper()));
        recycler.setAdapter(adapter);

效果圖:

在這裏插入圖片描述

StickyLayoutHelper

這個吸頂和吸底效果還是比較強大,自我感覺可以深入研究的就這個和FloatLayoutHelper了。具體代碼如下:

        VirtualLayoutManager manager = new VirtualLayoutManager(this);
        recycler.setLayoutManager(manager);
        DelegateAdapter adapter = new DelegateAdapter(manager, true);
        //在頂部時需先添加sticklayout,在底部時最後添加sticklayout
        StickyLayoutHelper helper = new StickyLayoutHelper(true);
//        adapter.addAdapter(new StickRecyclerAdapter(this, helper, recycler));
//        adapter.addAdapter(new DelegateRecyclerAdapter(this, new LinearLayoutHelper()));
          //頂部和實體合二爲一
        adapter.addAdapter(new DelegateRecyclerAdapter(this, helper));
        adapter.addAdapter(new DelegateRecyclerAdapter(this, new LinearLayoutHelper()));
          //底部
//        StickyLayoutHelper helper = new StickyLayoutHelper(false);
//        adapter.addAdapter(new DelegateRecyclerAdapter(this, new LinearLayoutHelper()));
//        adapter.addAdapter(new StickRecyclerAdapter(this, helper));
        recycler.setAdapter(adapter);


效果圖:頂部:

在這裏插入圖片描述
實體和頂部合二爲一:

在這裏插入圖片描述

總結


這個開源可以多個LayoutHelper進行結合,比之前那些LinearLayoutmanager、 Gridlayoutmanager之類的強大太多。我感覺有了這個。我之前那個SWPullRecyclerLayout可以在精煉,進行多方面佈局的結合來使用。現在,我們已經學會如何使用它的。之後我想我們就應該試着去看它的源碼來了解它是如何實現的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章