日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

项目接入实现复杂布局的vlayout

發(fā)布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 项目接入实现复杂布局的vlayout 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

  • V- Layout 是阿里出品的基礎(chǔ) UI 框架,用于快速實現(xiàn)頁面的復(fù)雜布局,在手機天貓 Android版 內(nèi)廣泛使用
電商圖
  • 讓人激動的是,在上個月V- Layout終于在Github上開源!

Github - alibaba - vlayout

Github
  • 在五一假期我對V- Layout進行了詳細分析,我將獻上一份 V- Layout的使用攻略 & 源碼分析,希望你們會喜歡。

閱讀本文前請先看:
Android Tangram模型:連淘寶、天貓都在用的UI框架模型你一定要懂


目錄

目錄

1. 為什么要使用 V - Layout

在講解 V - Layout 前,我們先來搞懂一個問題:為什么要使用 V - Layout

1.1 背景

  • Android中 UI 性能消耗主要來自于兩個方面:
  • 布局層次嵌套導(dǎo)致多重 measure/layout
  • View控件的創(chuàng)建和銷毀
    • 為了解決上述問題,現(xiàn)有的解決方式是:
    • 少用嵌套布局
    • 使用 ListView/GirdView/RecyclerView等基礎(chǔ)空間來處理View的回收與復(fù)用。

    但是,很多時候我們需要在一個長列表下做多種類型的布局來分配各種元素,,特別是電商平臺首頁等頁面,布局元素結(jié)構(gòu)更加復(fù)雜多樣。如下圖:

    電商圖

    此時的解決方案有所變化:不采用子View的復(fù)用,只采用一個主要的復(fù)用容器(如ListView 或 RecyclerView+LinearLayoutManager),然后在其中使用嵌套方式直接用各個組件進行拼接,減少了復(fù)用的能力

    1.2 問題

    這種做法還是會損失Android應(yīng)用的性能。

    1.3 解決方案

    • 通過自定義 LayoutManager 管理所有的布局類型
    • 即阿里出品的基礎(chǔ) UI 框架項目 VirtualLayout就是采用該方式來解決上述問題

    2. 簡介

    • 定義:VirtualLayout是阿里出品的基礎(chǔ) UI 框架項目
    • 作用:快速實現(xiàn)復(fù)雜的布局格式的混排 & 通過組件回收提高性能
    • 基于 RecyclerView & LayoutManager擴展
    • 目前已在Github開源:Github - alibaba - vlayout
    效果圖

    3. 應(yīng)用場景

    • 復(fù)雜的布局格式混排,如:浮動布局、欄格布局、通欄布局、一拖N布局、瀑布流布局,還可以組合使用這些布局
    • 具體場景是:如電商平臺首頁、活動頁等等

    V - Layout 目前已在手機天貓 & 淘寶 Android 版內(nèi)廣泛使用

    實際應(yīng)用效果圖

    4. 原理解析

    V - Layout的本質(zhì)原理是:通過自定義一個VirtualLayoutManager(繼承自 LayoutManager),用于管理一系列LayoutHelper,將具體的布局能力交給LayoutHelper來完成,從而 快速實現(xiàn)組合布局 的需求。

  • 每個 LayoutHelper負責(zé) 頁面某一個范圍內(nèi)的布局
  • V - Layout默認實現(xiàn)了10種默認布局:(對應(yīng)同名的LayoutHelper)
    布局類型
  • 4.1 源碼類說明

    • V - Layout的源碼類圖如下:

      UML類圖
    • 具體類說明

    示意圖
    • V - Layout默認實現(xiàn)了10種默認布局:(對應(yīng)同名的LayoutHelper)
    布局類型

    下面會進行詳細介紹。

    • 特別注意:
  • 每一種LayoutHelper負責(zé)布局一批組件范圍內(nèi)的組件,不同組件范圍內(nèi)的組件之間,如果類型相同,可以在滑動過程中回收復(fù)用。因此回收粒度比較細,且可以跨布局類型復(fù)用。
  • 支持擴展外部:即注冊新的LayoutHelper,實現(xiàn)特殊的布局方式。下面會詳細說明
  • 介紹完類之后,我將詳細分析 V - Layout的工作流程。


    4.2 工作流程

    • V - Layout的工作流程分為 初始化 & 布局流程。如下圖:
    工作流程
    • 下面我將對初始化 & 布局流程作詳細分析。

    4.2.1 初始化

    • 在使用 V - layout 快速實現(xiàn)復(fù)雜布局前,需要先做一系列的初始化工作。

    初始化流程與使用普通的 RecyclerView + LayoutManager 初始化流程基本一致:Vlayout的使用者

    初始化流程
    • 此處的初始化 實際上 就是 使用者在使用 V - layout 時需要做的初始化工作。
    • 此處主要先講解下數(shù)據(jù)列表的獲取:本質(zhì)上,是對頁面實體 進行 卡片 & 組件的拆解,形成一個位置列表
    示意圖
    • 其他初始化步驟將在下面實例講解進行詳細說明

    4.2.2 具體布局流程

    • 當(dāng)完成初始化工作后,每當(dāng)用戶剛打開頁面第一次渲染布局 或 用戶滑動頁面時,都會進行一次布局流程
    • 布局流程的本質(zhì)是:自定義 VirtualLayoutManager持續(xù)獲取頁面狀態(tài),并通過LayoutHelperFinder找到對應(yīng)的LayoutHelper從而實現(xiàn)對應(yīng)的布局邏輯,從而快速實現(xiàn)組合布局 的需求
    • 具體流程如下
    布局流程

    總結(jié)

    下面用一張圖總結(jié) V - Layout 的原理 & 工作流程

    原理 & 工作流程

    在講完原理后,接下來我將如何使用 V - Layout。


    5. 使用步驟

    • V - Layout的使用其實就是上面說的初始化工作
    • 使用步驟如下:
    使用步驟

    下面我將對每個步驟進行詳細說明。

    步驟1:創(chuàng)建RecyclerView & VirtualLayoutManager 對象并進行綁定

    recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);// 創(chuàng)建RecyclerView對象VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);// 創(chuàng)建VirtualLayoutManager對象// 同時內(nèi)部會創(chuàng)建一個LayoutHelperFinder對象,用來后續(xù)的LayoutHelper查找recyclerView.setLayoutManager(layoutManager);// 將VirtualLayoutManager綁定到recyclerView

    步驟2:設(shè)置回收復(fù)用池大小

    如果一屏內(nèi)相同類型的 View 個數(shù)比較多,需要設(shè)置一個合適的大小,防止來回滾動時重新創(chuàng)建 View)

    // 設(shè)置組件復(fù)用回收池RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();recyclerView.setRecycledViewPool(viewPool);viewPool.setMaxRecycledViews(0, 10);

    步驟3:設(shè)置Adapter

    設(shè)置 V - Layout的Adapter有兩種方式:

    • 方式1:繼承 自 DelegateAdapter
    • 方式2:繼承 自 VirtualLayoutAdapter
      下面會進行詳細說明:

    方式1:繼承 自 DelegateAdapter

    • 定義:DelegateAdapter是V - Layout專門為管理 LayoutHelper定制的 Adapter

    繼承自VirtualLayoutAdapter

    • 作用:通過管理不同布局的Adapter,繼而管理不同的 LayoutHelper,從而實現(xiàn)使用不同組合布局
  • 特別注意:雖不可直接綁定LayoutHelper,但是它內(nèi)部有一個繼承自RecyclerView.Adapter的內(nèi)部類Adapter可以綁定LayoutHelper;
  • 即通過一個List把綁定好的Adapter打包起來,再放去DelegateAdapter,這樣就可以實現(xiàn)組合使用不同的布局
    • 具體做法:
  • 寫法與復(fù)寫系統(tǒng)自帶的Adapter非常類似:只比系統(tǒng)自帶的RecyclerAdapter需要多重載onCreateLayoutHelper方法,其余類似
  • 關(guān)于Android系統(tǒng)自帶的RecyclerAdapter的使用具體請看我寫的文章Android開發(fā):ListView、AdapterView、RecyclerView全面解析
  • public class MyAdapter extends DelegateAdapter.Adapter<MyAdapter.MainViewHolder> {// 比系統(tǒng)自帶的RecyclerAdapter需要多重載onCreateLayoutHelper()@Overridepublic LayoutHelper onCreateLayoutHelper() {return layoutHelper;}... // 其余寫法與復(fù)寫系統(tǒng)自帶的Adapter相同 }

    方式2:繼承 自 VirtualLayoutAdapter

    • 定義:當(dāng)需要實現(xiàn)復(fù)雜需求時, 可以通過繼承VirtualLayoutAdapter從而實現(xiàn)自定義Adapter

    • 具體使用

    public class MyAdapter extends VirtualLayoutAdapter {...// 自定義Adapter邏輯 }

    步驟4:根據(jù)數(shù)據(jù)列表,創(chuàng)建對應(yīng)的LayoutHelper

    • 系統(tǒng)以封裝好以下布局類型(對應(yīng)同名的LayoutHelper)
    布局類型
    • 具體使用如下:

    1. 線性布局(LinearLayoutHelper)

    • 布局說明:布局子元素(Item)以線性排布的布局
    示意圖
    • 具體使用
    /**設(shè)置線性布局*/LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();// 創(chuàng)建對應(yīng)的LayoutHelper對象// 所有布局的公共屬性(屬性會在下面詳細說明)linearLayoutHelper.setItemCount(4);// 設(shè)置布局里Item個數(shù)linearLayoutHelper.setPadding(10,10,10,10);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離linearLayoutHelper.setMargin(10,10,10,10);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離linearLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色linearLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// linearLayoutHelper特有屬性linearLayoutHelper.setDividerHeight(1); // 設(shè)置每行Item的距離

    1. 所有布局的共有屬性說明:

    a. setItemCount屬性

    • 作用:設(shè)置整個布局里的Item數(shù)量

    如設(shè)置的Item總數(shù)如與Adapter的getItemCount()方法返回的數(shù)量不同,會取決于后者

    示意圖
    • 具體使用
    // 接口示意public void setItemCount(int Count)// 具體使用linearLayoutHelper.setItemCount(4);

    b. Adding & Margin屬性

    • 定義:都是邊距的含義,但二者邊距的定義不同:

    • Padding:是 LayoutHelper 的子元素相對 LayoutHelper 邊緣的距離;
    • Margin:是 LayoutHelper 邊緣相對父控件(即RecyclerView)的距離。具體如下圖:
      示意圖
    • 具體使用

    // 接口示意public void setPadding(int leftPadding, int topPadding, int rightPadding, int bottomPadding)public void setMargin(int leftMargin, int topMargin, int rightMargin, int bottomMargin)// 具體使用linearLayoutHelper.setPadding(10,10,10,10);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離linearLayoutHelper.setMargin(10,10,10,10);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離

    c. bgColor屬性

    • 作用:設(shè)置布局背景顏色
    • 具體使用:
    // 接口示意 public void setBgColor(int bgColor)// 具體使用 linearLayoutHelper.setBgColor(Color.YELLOW);

    d. aspectRatio屬性

    • 作用:設(shè)置布局內(nèi)每行布局的寬與高的比。如下圖
    示意圖
    • 具體使用
    // 接口示意 public void setAspectRatio(float aspectRatio); // LayoutHelper定義的aspectRatio((VirutalLayoutManager.LayoutParams) layoutParams).mAspectRatio // 視圖的LayoutParams定義的aspectRatio // 在LayoutHelper計算出視圖寬度之后,用來確定視圖高度時使用的,它會覆蓋通過LayoutHelper的aspectRatio計算出來的視圖高度,因此具備更高優(yōu)先級。// 具體使用linearLayoutHelper.setAspectRatio(6);

    2. LinearLayoutHelper布局的特有屬性說明

    a. dividerHeight屬性

    • 作用:設(shè)置每行Item之間的距離

    設(shè)置的間隔會與RecyclerView的addItemDecoration()添加的間隔疊加

    示意圖
    • 具體使用
    // 接口示意 public void setDividerHeight(int dividerHeight)// 具體使用linearLayoutHelper.setDividerHeight(1);

    2. 網(wǎng)格布局(GridLayout)

    • 布局說明:布局里的Item以網(wǎng)格的形式進行排列
    示意圖
    • 具體使用
    /**設(shè)置Grid布局*/GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(3);// 在構(gòu)造函數(shù)設(shè)置每行的網(wǎng)格個數(shù)// 公共屬性gridLayoutHelper.setItemCount(6);// 設(shè)置布局里Item個數(shù)gridLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離gridLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離gridLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色gridLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// gridLayoutHelper特有屬性(下面會詳細說明)gridLayoutHelper.setWeights(new float[]{40, 30, 30});//設(shè)置每行中 每個網(wǎng)格寬度 占 每行總寬度 的比例gridLayoutHelper.setVGap(20);// 控制子元素之間的垂直間距gridLayoutHelper.setHGap(20);// 控制子元素之間的水平間距gridLayoutHelper.setAutoExpand(false);//是否自動填充空白區(qū)域gridLayoutHelper.setSpanCount(3);// 設(shè)置每行多少個網(wǎng)格// 通過自定義SpanSizeLookup來控制某個Item的占網(wǎng)格個數(shù)gridLayoutHelper.setSpanSizeLookup(new GridLayoutHelper.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {if (position > 7 ) {return 3;// 第7個位置后,每個Item占3個網(wǎng)格}else {return 2;// 第7個位置前,每個Item占2個網(wǎng)格}}});
    GridLayoutHelper布局的特有屬性說明

    a. weights屬性

    • 作用:設(shè)置每行中每個網(wǎng)格寬度占每行總寬度的比例
  • 默認情況下,每行中每個網(wǎng)格中的寬度相等
  • weights屬性是一個float數(shù)組,每一項代表當(dāng)個網(wǎng)格占每行總寬度的百分比;總和是100,否則布局會超出容器寬度;
  • 如果布局中有4列,那么weights的長度也應(yīng)該是4;長度大于4,多出的部分不參與寬度計算;如果小于4,不足的部分默認平分剩余的空間。
  • 示意圖
    • 具體使用
    // 接口示意 public void setWeights(float[] weights)// 具體使用 gridLayoutHelper.setWeights(new float[]{40, 30, 30});

    b. vGap、hGap屬性

    • 作用:分別控制子元素之間的垂直間距 和 水平間距。
    示意圖
    • 具體使用
    // 接口示意public void setHGap(int hGap)public void setVGap(int vGap)// 具體使用gridLayoutHelper.setVGap(20);// 控制子元素之間的垂直間距gridLayoutHelper.setHGap(20);// 控制子元素之間的水平間距

    c. spanCount、spanSizeLookup屬性

    • 作用:
    • spanCount:設(shè)置每行多少個網(wǎng)格
    • spanSizeLookup:設(shè)置每個 Item占用多少個網(wǎng)格(默認= 1)
    示意圖
    • 具體使用
    // 接口示意 public void setSpanCount(int spanCount) public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup)// 具體使用gridLayoutHelper.setSpanCount(5);// 設(shè)置每行多少個網(wǎng)格// 通過自定義SpanSizeLookup來控制某個Item的占網(wǎng)格個數(shù)gridLayoutHelper.setSpanSizeLookup(new GridLayoutHelper.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {if (position > 7 ) {return 3;// 第7個位置后,每個Item占3個網(wǎng)格}else {return 2;// 第7個位置前,每個Item占2個網(wǎng)格}}});

    d. autoExpand屬性

    • 作用:當(dāng)一行里item的個數(shù) < (每行網(wǎng)格列數(shù) - spanCount值/ 每個Item占有2個網(wǎng)格-setSpanSizeLookup )時,是否自動填滿空白區(qū)域
  • 若autoExpand=true,那么視圖的總寬度會填滿可用區(qū)域;
  • 否則會在屏幕上留空白區(qū)域。
  • 示意圖
    • 具體使用
    // 接口示意 public void setAutoExpand(boolean isAutoExpand)// 具體使用 gridLayoutHelper.setAutoExpand(false);

    3. 固定布局(FixLayoutHelper)

    • 布局說明:布局里的Item 固定位置

    固定在屏幕某個位置,且不可拖拽 & 不隨頁面滾動而滾動。如下圖:(左上角)

    固定布局
    • 具體使用
    /**設(shè)置固定布局*/FixLayoutHelper fixLayoutHelper = new FixLayoutHelper(FixLayoutHelper.TOP_LEFT,40,100);// 參數(shù)說明:// 參數(shù)1:設(shè)置吸邊時的基準位置(alignType) - 有四個取值:TOP_LEFT(默認), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT// 參數(shù)2:基準位置的偏移量x// 參數(shù)3:基準位置的偏移量y// 公共屬性fixLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個數(shù)// 從設(shè)置Item數(shù)目的源碼可以看出,一個FixLayoutHelper只能設(shè)置一個 // @Override // public void setItemCount(int itemCount) { // if (itemCount > 0) { // super.setItemCount(1); // } else { // super.setItemCount(0); // } // }fixLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離fixLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離fixLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色fixLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// fixLayoutHelper特有屬性fixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);// 設(shè)置吸邊時的基準位置(alignType)fixLayoutHelper.setX(30);// 設(shè)置基準位置的橫向偏移量XfixLayoutHelper.setY(50);// 設(shè)置基準位置的縱向偏移量Y
    FixLayoutHelper特有屬性說明

    a. AlignType、x、y屬性

    • 作用:
    • alignType:吸邊基準類型
    • 共有4個取值:TOP_LEFT(默認), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,具體請看下面示意圖

    • x:基準位置的橫向偏移量
    • y:基準位置的縱向偏移量
    示意圖
    • 作用對象:FixLayoutHelper, ScrollFixLayoutHelper, FloatLayoutHelper的屬性
    // 接口示意 public void setAlignType(int alignType) public void setX(int x) public void setY(int y)// 具體使用 fixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT); fixLayoutHelper.setX(30); fixLayoutHelper.setY(50);

    4. 可選顯示的固定布局(ScrollFixLayoutHelper)

    • 布局說明:布局里的Item 固定位置
  • 固定在屏幕某個位置,且不可拖拽 & 不隨頁面滾動而滾動(繼承自固定布局(FixLayoutHelper))
  • 唯一不同的是,可以自由設(shè)置該Item什么時候顯示(到頂部顯示 / 到底部顯示),可如下圖:(左上角)
  • 需求場景:到頁面底部顯示”一鍵到頂部“的按鈕功能
  • 以下示意圖為:滑動到底部,布局才在左上角顯示

    滑動到底部才在左上角顯示
    • 具體使用
    /**設(shè)置可選固定布局*/ScrollFixLayoutHelper scrollFixLayoutHelper = new ScrollFixLayoutHelper(ScrollFixLayoutHelper.TOP_RIGHT,0,0);// 參數(shù)說明:// 參數(shù)1:設(shè)置吸邊時的基準位置(alignType) - 有四個取值:TOP_LEFT(默認), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT// 參數(shù)2:基準位置的偏移量x// 參數(shù)3:基準位置的偏移量y// 公共屬性scrollFixLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個數(shù)// 從設(shè)置Item數(shù)目的源碼可以看出,一個FixLayoutHelper只能設(shè)置一個 // @Override // public void setItemCount(int itemCount) { // if (itemCount > 0) { // super.setItemCount(1); // } else { // super.setItemCount(0); // } // }scrollFixLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離scrollFixLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離scrollFixLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色scrollFixLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// fixLayoutHelper特有屬性scrollFixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT);// 設(shè)置吸邊時的基準位置(alignType)scrollFixLayoutHelper.setX(30);// 設(shè)置基準位置的橫向偏移量XscrollFixLayoutHelper.setY(50);// 設(shè)置基準位置的縱向偏移量YscrollFixLayoutHelper.setShowType(ScrollFixLayoutHelper.SHOW_ON_ENTER);// 設(shè)置Item的顯示模式
    ScrollFixLayoutHelper特有屬性說明

    a. AlignType、x、y屬性

    • 作用:
    • alignType:吸邊基準類型
    • 共有4個取值:TOP_LEFT(默認), TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,具體請看下面示意圖

    • x:基準位置的橫向偏移量
    • y:基準位置的縱向偏移量
    示意圖
    • 具體使用
    // 接口示意 public void setAlignType(int alignType) public void setX(int x) public void setY(int y)// 具體使用 ScrollFixLayoutHelper.setAlignType(FixLayoutHelper.TOP_LEFT); ScrollFixLayoutHelper.setX(30); ScrollFixLayoutHelper.setY(50);

    b. ShowType屬性

    • 作用:設(shè)置Item的顯示模式

    共有三種顯示模式

  • SHOW_ALWAYS:永遠顯示(即效果同固定布局)
  • SHOW_ON_ENTER:默認不顯示視圖,當(dāng)頁面滾動到該視圖位置時才顯示;
  • SHOW_ON_LEAVE:默認不顯示視圖,當(dāng)頁面滾出該視圖位置時才顯示
    • 具體使用
    // 接口示意 public void setShowType(int showType)// 具體使用 scrollFixLayoutHelper.setShowType(ScrollFixLayoutHelper.SHOW_ON_ENTER);

    5. 浮動布局(FloatLayoutHelper)

    • 布局說明:布局里的Item只有一個
  • 可隨意拖動,但最終會被吸邊到兩側(cè)
  • 不隨頁面滾動而移動
  • 示意圖
    • 具體使用
    /**設(shè)置浮動布局*/FloatLayoutHelper floatLayoutHelper = new FloatLayoutHelper();// 創(chuàng)建FloatLayoutHelper對象// 公共屬性floatLayoutHelper.setItemCount(1);// 設(shè)置布局里Item個數(shù)// 從設(shè)置Item數(shù)目的源碼可以看出,一個FixLayoutHelper只能設(shè)置一個 // @Override // public void setItemCount(int itemCount) { // if (itemCount > 0) { // super.setItemCount(1); // } else { // super.setItemCount(0); // } // }floatLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離floatLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離floatLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色floatLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// floatLayoutHelper特有屬性floatLayoutHelper.setDefaultLocation(300,300);// 設(shè)置布局里Item的初始位置

    6. 欄格布局(ColumnLayoutHelper)

    • 布局說明:該布局只設(shè)有一欄(該欄設(shè)置多個Item)

    可理解為只有一行的線性布局

    示意圖/**設(shè)置欄格布局*/ColumnLayoutHelper columnLayoutHelper = new ColumnLayoutHelper();// 創(chuàng)建對象// 公共屬性columnLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個數(shù)columnLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離columnLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離columnLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色columnLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// columnLayoutHelper特有屬性columnLayoutHelper.setWeights(new float[]{30, 40, 30});// 設(shè)置該行每個Item占該行總寬度的比例// 同上面Weigths屬性講解

    7. 通欄布局(SingleLayoutHelper)

    • 布局說明:布局只有一欄,該欄只有一個Item
    示意圖
    • 具體使用
    /**設(shè)置通欄布局*/SingleLayoutHelper singleLayoutHelper = new SingleLayoutHelper();// 公共屬性singleLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個數(shù)singleLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離singleLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離singleLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色singleLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比

    8. 一拖N布局 (OnePlusNLayoutHelper)

    • 布局說明:將布局分為不同比例,最多是1拖4。具體如下圖
    示意圖1示意圖2
    • 具體使用
    /**設(shè)置1拖N布局*/OnePlusNLayoutHelper onePlusNLayoutHelper = new OnePlusNLayoutHelper(5);// 在構(gòu)造函數(shù)里傳入顯示的Item數(shù)// 最多是1拖4,即5個// 公共屬性onePlusNLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個數(shù)onePlusNLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離onePlusNLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離onePlusNLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色onePlusNLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比

    9. 吸邊布局(StickyLayoutHelper)

    • 布局說明:布局只有一個Item,顯示邏輯如下:

    • 當(dāng)它包含的組件處于屏幕可見范圍內(nèi)時,像正常的組件一樣隨頁面滾動而滾動
    • 當(dāng)組件將要被滑出屏幕返回的時候,可以吸到屏幕的頂部或者底部,實現(xiàn)一種吸住的效果
    • 示意圖(吸在頂部)

    示意圖
    • 具體使用
    /**設(shè)置吸邊布局*/StickyLayoutHelper stickyLayoutHelper = new StickyLayoutHelper();// 公共屬性stickyLayoutHelper.setItemCount(3);// 設(shè)置布局里Item個數(shù)stickyLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離stickyLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離stickyLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色stickyLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// 特有屬性stickyLayoutHelper.setStickyStart(true);// true = 組件吸在頂部// false = 組件吸在底部stickyLayoutHelper.setOffset(100);// 設(shè)置吸邊位置的偏移量Adapter_StickyLayout = new MyAdapter(this, stickyLayoutHelper,1, listItem) {// 設(shè)置需要展示的數(shù)據(jù)總數(shù),此處設(shè)置是1// 為了展示效果,通過重寫onBindViewHolder()將布局的第一個數(shù)據(jù)設(shè)置為Stick@Overridepublic void onBindViewHolder(MainViewHolder holder, int position) {super.onBindViewHolder(holder, position);if (position == 0) {holder.Text.setText("Stick");}}};adapters.add(Adapter_StickyLayout) ;// 將當(dāng)前的Adapter加入到Adapter列表里

    stickyStart、 offset屬性說明

    • 作用:

    • stickyStart:設(shè)置吸邊位置
    • 當(dāng)視圖的位置在屏幕范圍內(nèi)時,視圖會隨頁面滾動而滾動;當(dāng)視圖的位置滑出屏幕時,StickyLayoutHelper會將視圖固定在頂部(stickyStart = true)或 底部(stickyStart = false)

    • offset:設(shè)置吸邊的偏移量
    • 具體使用

    // 接口示意public void setStickyStart(boolean stickyStart)public void setOffset(int offset)// 具體使用stickyLayoutHelper.setStickyStart(true);// true = 組件吸在頂部// false = 組件吸在底部stickyLayoutHelper.setOffset(100);// 設(shè)置吸邊位置的偏移量

    10. 瀑布流布局(StaggeredGridLayoutHelper)

    • 布局說明:以網(wǎng)格的形式進行布局。與網(wǎng)格布局類似,區(qū)別在于:
      • 網(wǎng)格布局每欄的Item高度是相等的;
      • 瀑布流布局每欄的Item高度是可以不相等的。
    示意圖
    • 具體使用
    /**設(shè)置瀑布流布局*/StaggeredGridLayoutHelper staggeredGridLayoutHelper = new StaggeredGridLayoutHelper();// 創(chuàng)建對象// 公有屬性staggeredGridLayoutHelper.setItemCount(20);// 設(shè)置布局里Item個數(shù)staggeredGridLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離staggeredGridLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離staggeredGridLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色staggeredGridLayoutHelper.setAspectRatio(3);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// 特有屬性staggeredGridLayoutHelper.setLane(3);// 設(shè)置控制瀑布流每行的Item數(shù)staggeredGridLayoutHelper.setHGap(20);// 設(shè)置子元素之間的水平間距staggeredGridLayoutHelper.setVGap(15);// 設(shè)置子元素之間的垂直間距

    自定義布局(即自定義LayoutHelper)

    除了使用系統(tǒng)提供的默認布局 LayoutHelper,開發(fā)者還可以通過自定義LayoutHelper從而實現(xiàn)自定義布局樣式。有三種方式:

  • 繼承BaseLayoutHelper:從上而下排列的順序 & 內(nèi)部 View可以按行回收的布局;主要實現(xiàn)layoutViews()、computeAlignOffset()等方法
  • LinearLayoutHelper、GridLayoutHelper都是采用該方法實現(xiàn)

  • 繼承AbstractFullFillLayoutHelper:有些布局內(nèi)部的 View 并不是從上至下排列的順序(即 Adatper 里的數(shù)據(jù)順序和物理視圖順序不一致,那么可能就不能按數(shù)據(jù)順序布局和回收),需要一次性布局
    & 回收。主要實現(xiàn)layoutViews()等方法
  • OnePlusNLayoutHelper采用該方法實現(xiàn)

  • 繼承FixAreaLayoutHelper:fix 類型布局,子節(jié)點不隨頁面滾動而滾動。主要實現(xiàn)layoutViews()、beforeLayout()、afterLayout()等方法
  • FixLayoutHelper采用該方法實現(xiàn)


    步驟5:將生成的LayoutHelper 交給Adapter,并綁定到RecyclerView 對象

    此處的做法會因步驟3中Adapter的設(shè)置而有所不同

    <-- Adapter繼承 自 DelegateAdapter -->// 步驟1:設(shè)置Adapter列表(同時也是設(shè)置LayoutHelper列表)List<DelegateAdapter.Adapter> adapters = new LinkedList<>();// 步驟2:創(chuàng)建自定義的Adapter對象 & 綁定數(shù)據(jù) & 綁定上述對應(yīng)的LayoutHelper // 綁定你需要展示的布局LayoutHelper即可,此處僅展示兩個。MyAdapter Adapter_linearLayout = new MyAdapter(this, linearLayoutHelper,ListItem); // ListItem是需要綁定的數(shù)據(jù)(其實取決于你的Adapter如何定義)MyAdapter Adapter_gridLayoutHelper = new MyAdapter(this, gridLayoutHelper,ListItem);// 步驟3:將創(chuàng)建的Adapter對象放入到DelegateAdapter.Adapter列表里adapters.add(Adapter_linearLayout ) ;adapters.add(Adapter_gridLayoutHelper ) ;// 步驟4:創(chuàng)建DelegateAdapter對象 & 將layoutManager綁定到DelegateAdapter DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager);// 步驟5:將DelegateAdapter.Adapter列表綁定到DelegateAdapterdelegateAdapter.setAdapters(adapters);// 步驟6:將delegateAdapter綁定到recyclerView recyclerView.setAdapter(delegateAdapter);<-- Adapter繼承 自 VirtualLayoutAdapter -->// 步驟1:設(shè)置LayoutHelper列表List<LayoutHelper> helpers = new LinkedList<>();// 步驟2:綁定上述對應(yīng)的LayoutHelper helpers.add(Adapter_linearLayout ); helpers.add(Adapter_gridLayoutHelper ) ;// 步驟3:創(chuàng)建自定義的MyAdapter對象 & 綁定layoutManager MyAdapter myAdapter = new MyAdapter(layoutManager);// 步驟4:將 layoutHelper 列表傳遞給 adapter myAdapter.setLayoutHelpers(helpers);// 步驟5:將adapter綁定到recyclerView recycler.setAdapter(myAdapter);

    至此,使用過程講解完畢。


    6. 實例說明

    • V-Layout的優(yōu)點在于快速的組合不同布局
    • 下面,我將根據(jù)上面的步驟說明,用一個實例來使用 V - Layout快速組合布局

    步驟1:在Android - Gradle加入依賴

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

    步驟2:定義主 xml布局

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="scut.carson_ho.v_layoutusage.MainActivity"><android.support.v7.widget.RecyclerViewandroid:id="@+id/my_recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:scrollbars="horizontal" /> </RelativeLayout>

    步驟3:定義 RecyclerView每個子元素( Item )的xml布局

    item.xml

    此處定義的 Item 布局是常用的 上字下圖

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="New Text"android:id="@+id/Item" /><ImageViewandroid:layout_alignParentRight="true"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/Image"/></LinearLayout>

    步驟4:設(shè)置Adapter

    • 設(shè)置 V - Layout的Adapter有兩種方式:
    • 繼承 自 DelegateAdapter

    此處主要以該方式進行演示

  • 繼承 自 VirtualLayoutAdapter
    • 具體使用

    MyAdapter.java

    public class MyAdapter extends DelegateAdapter.Adapter<MyAdapter.MainViewHolder> {// 使用DelegateAdapter首先就是要自定義一個它的內(nèi)部類Adapter,讓LayoutHelper和需要綁定的數(shù)據(jù)傳進去// 此處的Adapter和普通RecyclerView定義的Adapter只相差了一個onCreateLayoutHelper()方法,其他的都是一樣的做法.private ArrayList<HashMap<String, Object>> listItem;// 用于存放數(shù)據(jù)列表private Context context;private LayoutHelper layoutHelper;private RecyclerView.LayoutParams layoutParams;private int count = 0;private MyItemClickListener myItemClickListener;// 用于設(shè)置Item點擊事件//構(gòu)造函數(shù)(傳入每個的數(shù)據(jù)列表 & 展示的Item數(shù)量)public MyAdapter(Context context, LayoutHelper layoutHelper, int count, ArrayList<HashMap<String, Object>> listItem) {this(context, layoutHelper, count, new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300), listItem);}public MyAdapter(Context context, LayoutHelper layoutHelper, int count, @NonNull RecyclerView.LayoutParams layoutParams, ArrayList<HashMap<String, Object>> listItem) {this.context = context;this.layoutHelper = layoutHelper;this.count = count;this.layoutParams = layoutParams;this.listItem = listItem;}// 把ViewHolder綁定Item的布局@Overridepublic MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {return new MainViewHolder(LayoutInflater.from(context).inflate(R.layout.item, parent, false));}// 此處的Adapter和普通RecyclerView定義的Adapter只相差了一個onCreateLayoutHelper()方法@Overridepublic LayoutHelper onCreateLayoutHelper() {return layoutHelper;}// 綁定Item的數(shù)據(jù)@Overridepublic void onBindViewHolder(MainViewHolder holder, int position) {holder.Text.setText((String) listItem.get(position).get("ItemTitle"));holder.image.setImageResource((Integer) listItem.get(position).get("ItemImage"));}// 返回Item數(shù)目@Overridepublic int getItemCount() {return count;}// 設(shè)置Item的點擊事件// 綁定MainActivity傳進來的點擊監(jiān)聽器public void setOnItemClickListener(MyItemClickListener listener) {myItemClickListener = listener;}//定義Viewholderclass MainViewHolder extends RecyclerView.ViewHolder {public TextView Text;public ImageView image;public MainViewHolder(View root) {super(root);// 綁定視圖Text = (TextView) root.findViewById(R.id.Item);image = (ImageView) root.findViewById(R.id.Image);root.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (myItemClickListener != null)myItemClickListener.onItemClick(v, getPosition());}}//監(jiān)聽到點擊就回調(diào)MainActivity的onItemClick函數(shù));}public TextView getText() {return Text;}} }

    以下步驟都將寫在同一個.Java文件里

    步驟5:創(chuàng)建RecyclerView & VirtualLayoutManager 對象并進行綁定
    步驟6:設(shè)置回收復(fù)用池大小
    步驟7:設(shè)置需要存放的數(shù)據(jù)
    步驟8:根據(jù)數(shù)據(jù)列表,創(chuàng)建對應(yīng)的LayoutHelper
    步驟9:將生成的LayoutHelper 交給Adapter,并綁定到RecyclerView 對象

    詳細請看注釋

    MainActivity.java

    public class MainActivity extends AppCompatActivity implements MyItemClickListener {RecyclerView recyclerView;MyAdapter Adapter_linearLayout,Adapter_GridLayout,Adapter_FixLayout,Adapter_ScrollFixLayout,Adapter_FloatLayout,Adapter_ColumnLayout,Adapter_SingleLayout,Adapter_onePlusNLayout,Adapter_StickyLayout,Adapter_StaggeredGridLayout;private ArrayList<HashMap<String, Object>> listItem;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);/*** 步驟1:創(chuàng)建RecyclerView & VirtualLayoutManager 對象并進行綁定* */recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);// 創(chuàng)建RecyclerView對象VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);// 創(chuàng)建VirtualLayoutManager對象// 同時內(nèi)部會創(chuàng)建一個LayoutHelperFinder對象,用來后續(xù)的LayoutHelper查找recyclerView.setLayoutManager(layoutManager);// 將VirtualLayoutManager綁定到recyclerView/*** 步驟2:設(shè)置組件復(fù)用回收池* */RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();recyclerView.setRecycledViewPool(viewPool);viewPool.setMaxRecycledViews(0, 10);/*** 步驟3:設(shè)置需要存放的數(shù)據(jù)* */listItem = new ArrayList<HashMap<String, Object>>();for (int i = 0; i < 100; i++) {HashMap<String, Object> map = new HashMap<String, Object>();map.put("ItemTitle", "第" + i + "行");map.put("ItemImage", R.mipmap.ic_launcher);listItem.add(map);}/*** 步驟4:根據(jù)數(shù)據(jù)列表,創(chuàng)建對應(yīng)的LayoutHelper* */// 為了展示效果,此處將上面介紹的所有布局都顯示出來/**設(shè)置線性布局*/LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();// 創(chuàng)建對應(yīng)的LayoutHelper對象// 公共屬性linearLayoutHelper.setItemCount(4);// 設(shè)置布局里Item個數(shù)linearLayoutHelper.setPadding(20, 20, 20, 20);// 設(shè)置LayoutHelper的子元素相對LayoutHelper邊緣的距離linearLayoutHelper.setMargin(20, 20, 20, 20);// 設(shè)置LayoutHelper邊緣相對父控件(即RecyclerView)的距離// linearLayoutHelper.setBgColor(Color.GRAY);// 設(shè)置背景顏色linearLayoutHelper.setAspectRatio(6);// 設(shè)置設(shè)置布局內(nèi)每行布局的寬與高的比// linearLayoutHelper特有屬性linearLayoutHelper.setDividerHeight(10);// 設(shè)置間隔高度// 設(shè)置的間隔會與RecyclerView的addItemDecoration()添加的間隔疊加.linearLayoutHelper.setMarginBottom(100);// 設(shè)置布局底部與下個布局的間隔// 創(chuàng)建自定義的Adapter對象 & 綁定數(shù)據(jù) & 綁定對應(yīng)的LayoutHelper進行布局繪制Adapter_linearLayout = new MyAdapter(this, linearLayoutHelper, 4, listItem) {// 參數(shù)2:綁定綁定對應(yīng)的LayoutHelper// 參數(shù)3:傳入該布局需要顯示的數(shù)據(jù)個數(shù)// 參數(shù)4:傳入需要綁定的數(shù)據(jù)// 通過重寫onBindViewHolder()設(shè)置更豐富的布局效果@Overridepublic void onBindViewHolder(MainViewHolder holder, int position) {super.onBindViewHolder(holder, position);// 為了展示效果,將布局的第一個數(shù)據(jù)設(shè)置為linearLayoutif (position == 0) {holder.Text.setText("Linear");}//為了展示效果,將布局里不同位置的Item進行背景顏色設(shè)置if (position < 2) {holder.itemView.setBackgroundColor(0x66cc0000 + (position - 6) * 128);} else if (position % 2 == 0) {holder.itemView.setBackgroundColor(0xaa22ff22);} else {holder.itemView.setBackgroundColor(0xccff22ff);}}};Adapter_linearLayout.setOnItemClickListener(this);// 設(shè)置每個Item的點擊事件....// 還有其他布局,由于代碼量就較多就不貼出來了。/***步驟5:將生成的LayoutHelper 交給Adapter,并綁定到RecyclerView 對象**/// 1. 設(shè)置Adapter列表(同時也是設(shè)置LayoutHelper列表)List<DelegateAdapter.Adapter> adapters = new LinkedList<>();// 2. 將上述創(chuàng)建的Adapter對象放入到DelegateAdapter.Adapter列表里adapters.add(Adapter_linearLayout) ;adapters.add(Adapter_StickyLayout) ;adapters.add(Adapter_ScrollFixLayout) ;adapters.add(Adapter_GridLayout) ;adapters.add(Adapter_FixLayout) ;adapters.add(Adapter_FloatLayout) ;adapters.add(Adapter_ColumnLayout) ;adapters.add(Adapter_SingleLayout) ;adapters.add(Adapter_onePlusNLayout) ;adapters.add(Adapter_StaggeredGridLayout) ;// 3. 創(chuàng)建DelegateAdapter對象 & 將layoutManager綁定到DelegateAdapterDelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager);// 4. 將DelegateAdapter.Adapter列表綁定到DelegateAdapterdelegateAdapter.setAdapters(adapters);// 5. 將delegateAdapter綁定到recyclerViewrecyclerView.setAdapter(delegateAdapter);/***步驟6:Item之間的間隔**/recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {outRect.set(5, 5, 5, 5);}});}/***步驟7:實現(xiàn)Item點擊事件**/// 點擊事件的回調(diào)函數(shù)@Overridepublic void onItemClick(View view, int postion) {System.out.println("點擊了第"+postion+"行");Toast.makeText(this, (String) listItem.get(postion).get("ItemTitle"), Toast.LENGTH_SHORT).show();} }

    效果圖

    總效果圖

    源碼地址

    Carson_Ho的Github地址:V - Layout

    參考文檔:
    https://github.com/alibaba/vlayout
    http://pingguohe.net/2017/02/28/vlayout-design.html



    作者:Carson_Ho
    鏈接:https://www.jianshu.com/p/6b658c8802d1
    來源:簡書
    著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

    總結(jié)

    以上是生活随笔為你收集整理的项目接入实现复杂布局的vlayout的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。