什么是VLayout

VLayout全称Virtual Layout Manager,是由阿里发布的一个针对RecyclerView的LayoutManager扩展库

它提供了若干种常用的布局,并支持多种不同的布局,按线性的方式进行组合

使用案例

以淘宝首页为例,整个页面只需要一个RecyclerView即可完成

这是因为VLayout使用的是加强型的DelegateAdapter,它能够对多个子DelegateAdapter进行组合


VLayout十大布局

  • LinearLayoutHelper:线性布局

  • GridLayoutHelper:网格布局

  • FixLayoutHelper:固定布局,始终在屏幕固定位置显示

  • ScrollFixLayoutHelper:固定布局,当页面滑动到指定位置时才显示,可以用来做返回顶部或书签等功能

  • FloatLayoutHelper:浮动布局,浮动显示在屏幕上,用户可以拖拽其位置

  • ColumnLayoutHelper:栏格布局,所有元素排在一排,可配置不同列之间的宽度比

  • SingleLayoutHelper:通栏布局,显示和页面等宽的单个元素

  • OnePlusNLayoutHelper:一加N布局,左侧一个主元素,右侧N个子元素

  • StickyLayoutHelper:吸附布局, 吸附在布局顶部或底部

  • StaggeredGridLayoutHelper:瀑布流布局,一行铺满,自动摆到下一行

核心代码

package com.example.administrator.taobao;import android.graphics.Color;import android.os.Bundle;import android.widget.ImageView;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.RecyclerView;import com.alibaba.android.vlayout.DelegateAdapter;import com.alibaba.android.vlayout.VirtualLayoutManager;import com.alibaba.android.vlayout.layout.GridLayoutHelper;import com.alibaba.android.vlayout.layout.LinearLayoutHelper;import com.alibaba.android.vlayout.layout.OnePlusNLayoutHelper;import com.bumptech.glide.Glide;import com.chad.library.adapter.base.BaseViewHolder;import com.sunfusheng.marqueeview.MarqueeView;import com.youth.banner.Banner;import com.youth.banner.BannerConfig;import com.youth.banner.Transformer;import java.util.Arrays;import java.util.LinkedList;import java.util.List;@SuppressWarnings("all")public class MainActivity extends AppCompatActivity {//不同类型的ViewTypeint VIEW_TYPE_BANNER = 1;int VIEW_TYPE_APP = 2;int VIEW_TYPE_NEWS = 3;int VIEW_TYPE_GOOD_TITLE = 4;int VIEW_TYPE_GOOD_THUMB = 5;//横幅位String[] bannerUrls = {"https://img-blog.csdnimg.cn/03f90fd773d846de926b335276b9bdc6.gif", "https://img-blog.csdnimg.cn/03f90fd773d846de926b335276b9bdc6.gif"};//应用位String[] appTitles = {"天猫", "聚划算", "天猫国际", "外卖", "天猫超市", "充值中心", "飞猪旅行", "领金币", "拍卖", "分类"};int[] appIcons = {R.mipmap.ic_tian_mao, R.mipmap.ic_ju_hua_suan, R.mipmap.ic_tian_mao_guoji, R.mipmap.ic_waimai, R.mipmap.ic_chaoshi, R.mipmap.ic_voucher_center, R.mipmap.ic_travel, R.mipmap.ic_tao_gold, R.mipmap.ic_auction, R.mipmap.ic_classify};//新闻位String[] newsUrls1 = {"天猫超市最近发大活动啦,快来抢", "没有最便宜,只有更便宜!"};String[] newsUrls2 = {"天猫超市最近发大活动啦,快来抢", "没有最便宜,只有更便宜!"};//商品位int[] goodTitles = {R.mipmap.item1, R.mipmap.item2, R.mipmap.item3, R.mipmap.item4, R.mipmap.item5};int[] goodThumbs = {R.mipmap.flashsale1, R.mipmap.flashsale2, R.mipmap.flashsale3, R.mipmap.flashsale4};RecyclerView recyclerView;List<DelegateAdapter.Adapter> subAdapters = new LinkedList();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {recyclerView = findViewById(R.id.recycler);//1.设置总布局管理器VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);recyclerView.setLayoutManager(layoutManager);//2.设置回收池大小(相同类型的View可以复用,防止多次创建ItemView)RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();viewPool.setMaxRecycledViews(0, 10);recyclerView.setRecycledViewPool(viewPool);//3.逐个设置子模块适配器addBannerAdapter();addAppAdapter();addNewsAdapter();addGoodAdapter();//4.设置总适配器DelegateAdapter mainAdapter = new DelegateAdapter(layoutManager, true);mainAdapter.setAdapters(subAdapters);recyclerView.setAdapter(mainAdapter);}//添加子适配器:商品位private void addGoodAdapter() {for (int i = 0; i < goodTitles.length; i++) {//商品标题int goodTitle = goodTitles[i];LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();SubAdapter titleAdapter = new SubAdapter(this, linearLayoutHelper, R.layout.vlayout_title, 1, VIEW_TYPE_GOOD_TITLE) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);holder.setImageResource(R.id.iv, goodTitle);}};subAdapters.add(titleAdapter);//商品列表OnePlusNLayoutHelper onePlusNLayoutHelper = new OnePlusNLayoutHelper(4);onePlusNLayoutHelper.setBgColor(Color.WHITE);SubAdapter girdAdapter = new SubAdapter(this, onePlusNLayoutHelper, R.layout.vlayout_image, 4, VIEW_TYPE_GOOD_THUMB) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);int item = goodThumbs[position];ImageView iv = holder.getView(R.id.iv);Glide.with(getApplicationContext()).load(item).into(iv);}};subAdapters.add(girdAdapter);}}//添加子适配器:新闻位private void addNewsAdapter() {LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();SubAdapter newsAdapter = new SubAdapter(this, linearLayoutHelper, R.layout.vlayout_news, 1, VIEW_TYPE_NEWS) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);MarqueeView marqueeView1 = holder.getView(R.id.marqueeView1);MarqueeView marqueeView2 = holder.getView(R.id.marqueeView2);marqueeView1.startWithList(Arrays.asList(newsUrls1));marqueeView2.startWithList(Arrays.asList(newsUrls2));marqueeView1.startWithList(Arrays.asList(newsUrls1), R.anim.anim_bottom_in, R.anim.anim_top_out);marqueeView2.startWithList(Arrays.asList(newsUrls2), R.anim.anim_bottom_in, R.anim.anim_top_out);}};subAdapters.add(newsAdapter);}//添加子适配器:应用位private void addAppAdapter() {GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(5);gridLayoutHelper.setBgColor(Color.WHITE);SubAdapter appAdapter = new SubAdapter(this, gridLayoutHelper, R.layout.vlayout_menu, 10, VIEW_TYPE_APP) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);holder.setText(R.id.tv_menu_title_home, appTitles[position] + "");holder.setImageResource(R.id.iv_menu_home, appIcons[position]);}};subAdapters.add(appAdapter);}//添加子适配器:横幅位private void addBannerAdapter() {LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();SubAdapter bannerAdapter = new SubAdapter(this, linearLayoutHelper, R.layout.vlayout_banner, 1, VIEW_TYPE_BANNER) {@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position);Banner banner = holder.getView(R.id.banner);banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);banner.setImageLoader(new GlideImageLoader());banner.setImages(Arrays.asList(bannerUrls));banner.setBannerAnimation(Transformer.DepthPage);banner.isAutoPlay(true);banner.setDelayTime(5000);banner.setIndicatorGravity(BannerConfig.CENTER);banner.start();}};subAdapters.add(bannerAdapter);}}

VLayout工作原理

  • SubAdapter:负责将单个模块的Data转成View

  • SubLayoutHelper:负责对子模块内的ItemView进行布局

  • MainAdapter:对所有SubAdapter的数据进行整合,形成新的DataSet,并分配新的Position和ViewType。RecyclerView向MainAdapter取数据时,MainAdapter再通过所有SubAdapter逆查找数据

  • VirtualLayoutManager:完成总模块的布局功能,LayoutManager通过MainAdapter可以找到ItemView对应的SubAdapter,再将ItemView的布局工作,交给SubAdapter对应的SubLayoutHelper处理即可

  • SubAdapter和MainAdapter都继承自DelegateAdapter

  • VirtualLayoutManager本身是一个线性布局

VLayout核心函数工作流程

  • RecyclerView.setLayoutManager => RecyclerView.requestLayout

  • RecyclerView.setAdapter => RecyclerView.requestLayout

  • RecyclerView.requestLayout => RecyclerView.onLayout => RecyclerView.dispatchLayout => RecyclerView.dispatchLayoutStep2 => VirtualLayoutManager.onLayoutChildren

  • VirtualLayoutManager.onLayoutChildren => ExposeLinearLayoutManagerEx.onLayoutChildren(基类方法) => ExposeLinearLayoutManagerEx.fill => ExposeLinearLayoutManagerEx.layoutChunk

  • VirtualLayoutManager.layoutChunk(组装所有ItemView) => LayoutHelper.doLayout(调用子模块的LayoutHelper来布局ItemView) => LayoutHelper.layoutViews

  • LayoutHelper.layoutViews => BaseLayoutHelper.nextView => LayoutState.next => Recycler.getViewForPosition => Recycler.tryBindViewHolderByDeadline => Adapter.createViewHolder/Adapter.bindViewHolder

源码下载

阿里VLayout.zip

【高级UI】【031】阿里VLayout使用和源码解析相关推荐

  1. Nacos高级特性Raft算法以及原理和源码分析

    Nacos高级特性Raft算法以及原理和源码分析 对比springcloud-config配置中心 springcloud-config工作原理 Nacos的工作原理图 springcloud-con ...

  2. Google Test(GTest)使用方法和源码解析——模板类测试技术分析和应用

    写C++难免会遇到模板问题,如果要针对一个模板类进行测试,似乎之前博文中介绍的方式只能傻乎乎的一个一个特化类型后再进行测试.其实GTest提供了两种测试模板类的方法,本文我们将介绍方法的使用,并分析其 ...

  3. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  4. vue3中使用lulu-UI和源码解析

    vue3中使用lulu-UI和源码解析 前言 本文分析的是LuLu UI的Edge主题,这是张鑫旭开发的一套UI组件,使用原生JavaScript编写,使用了JavaScript和CSS前沿的新语法和 ...

  5. Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用

    在我们设计测试用例时,我们需要考虑很多场景.每个场景都可能要细致地考虑到到各个参数的选择.比如我们希望使用函数IsPrime检测10000以内字的数字,难道我们要写一万行代码么?(转载请指明出于bre ...

  6. Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析

    有些时候,我们不仅要测试类暴露出来的公有方法,还要测试其受保护的或者私有方法.GTest测试框架提供了一种方法,让我们可以测试类的私有方法.但是这是一种侵入式的,会破坏原来代码的结构,所以我觉得还是谨 ...

  7. Google Test(GTest)使用方法和源码解析——预处理技术分析和应用

    预处理 在<Google Test(GTest)使用方法和源码解析--概况>最后一部分,我们介绍了GTest的预处理特性.现在我们就详细介绍该特性的使用和相关源码.(转载请指明出于brea ...

  8. Google Test(GTest)使用方法和源码解析——断言的使用方法和解析

    在之前博文的基础上,我们将介绍部分断言的使用,同时穿插一些源码.(转载请指明出于breaksoftware的csdn博客) 断言(Assertions) 断言是GTest局部测试中最简单的使用方法,我 ...

  9. Google Test(GTest)使用方法和源码解析——Listener技术分析和应用

    在<Google Test(GTest)使用方法和源码解析--结果统计机制分析>文中,我么分析了GTest如何对测试结果进行统计的.本文我们将解析其结果输出所使用到的Listener机制. ...

最新文章

  1. Linux操作系统下查看硬件信息的命令总结
  2. 从JAVA转学习Go——Go在eclipse的环境搭建
  3. 在知乎引发众多分布式数据库大佬争相回答的问题
  4. 记一次应急响应到溯源入侵者
  5. VBSCRIPT的循环挺好理解的
  6. 某考试 T1 arg
  7. HDU1425 sort【排序】
  8. HTML5 Canvas JavaScript库 Fabric.js 使用经验
  9. MapReduce入门(二)合并小文件
  10. C# 使用Newtonsoft.Json读写Json文件
  11. python设计模式之工厂模式概述
  12. Android 如何查看apk签名信息的MD5(SHA1和SHA256也可以)
  13. Linux重定向console口控制台,Linux重定向console口控制台(Fedora)
  14. jira迁移问题解决(实践篇)
  15. irq : nobody cared (try booting with the “irqpoll“ option) 问题说明
  16. netcore在Linux后台运行at Interop.ThrowExceptionForIoErrno
  17. 微信群红包模拟器-怎样抢最大的红包
  18. 矩阵的迹\矩阵的秩\伴随矩阵\共轭矩阵,基底、维数与秩,相对某个基底的坐标计算方法
  19. 木材防霉剂预防木材发霉方法
  20. (数组)88. 合并两个有序数组(java)

热门文章

  1. 华为鸿蒙系统兼容测试方法
  2. 认识volatile关键字
  3. MySQL —— if分支判断语句和case when判断语句
  4. 用c++写出带交互界面的简单计算器
  5. IDEA中字体大小无法更改解决办法
  6. 软件公司发展的五种模式[原创]
  7. 创建boot项目卡在resolving dependenciesof
  8. 设计一个银行账户类,可以存钱、取钱、查钱、获取开户日期 内有测试类
  9. 玩转CSS中块元素、内联元素、内联块元素
  10. 网页禁止复制的解决方法