android VLayout 全面解析

博观而约取,厚积而薄发。这篇文章主要讲述android VLayout 全面解析相关的知识,希望能为你提供帮助。
概述 前不久, 阿里新开源了2个东西, Atlas和vlayout。今天我来介绍下vlayout的使用。在介绍前, 先抱怨两句, 阿里放开源出来, 感觉就是让我们这群人给他们找bug~~我曾遇到一个奇怪的问题, 然后一直以为自己写的有问题, 结果去down了官方demo跑了一下, 结果官方的demo居然并没有做这个效果~不解! !
好了, 话不多说, 我会通过官方的介绍以及自己的写的demo一一介绍。先放上官方的github地址: https://github.com/alibaba/vlayout
VLayout简介 vlayout全称VirtualLayout, 它是一个针对RecyclerView的LayoutManager扩展, 主要提供一整套布局方案和布局间的组件复用的问题。它通过定制化的LayoutManager, 接管整个RecyclerView的布局逻辑; LayoutManager管理了一系列LayoutHelper, LayoutHelper负责具体布局逻辑实现的地方; 每一个LayoutHelper负责页面某一个范围内的组件布局; 不同的LayoutHelper可以做不同的布局逻辑, 因此可以在一个RecyclerView页面里提供异构的布局结构, 这就能比系统自带的LinearLayoutManager、GridLayoutManager等提供更加丰富的能力。同时支持扩展LayoutHelper来提供更多的布局能力。
主要功能

  • 默认通用布局实现, 解耦所有的View和布局之间的关系: Linear, Grid, 吸顶, 浮动, 固定位置等
    1: LinearLayoutHelper: 线性布局
    2: GridLayoutHelper: Grid布局, 支持横向的colspan
    3: FixLayoutHelper: 固定布局, 始终在屏幕固定位置显示
    4: ScrollFixLayoutHelper: 固定布局, 但之后当页面滑动到该图片区域才显示, 可以用来做返回顶部或其他书签等
    5: FloatLayoutHelper: 浮动布局, 可以固定显示在屏幕上, 但用户可以拖拽其位置
    6: ColumnLayoutHelper: 栏格布局, 都布局在一排, 可以配置不同列之间的宽度比值
    7: SingleLayoutHelper: 通栏布局, 只会显示一个组件View
    8: 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 }

或者maven
< dependency> < groupId> com.alibaba.android< /groupId> < artifactId> vlayout< /artifactId> < version> 1.0.3< /version> < type> aar< /type> < /dependency>

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内部没有相对位置关系, 不处理边距。
    android VLayout 全面解析

    文章图片
对于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实现这个特性。
android VLayout 全面解析

文章图片

使用背景色
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计算出来的视图高度, 因此具备更高优先级。
    android VLayout 全面解析

    文章图片
对于LayoutHelper, 调用
public void setAspectRatio(float aspectRatio)

对于LayoutParams, 调用
((VirutalLayoutManager.LayoutParams) layoutParams).mAspectRatio

dividerHeight
LinearLayoutHelper的属性, LinearLayoutHelper是像ListView一样的线性布局, dividerHeight就是每个组件之间的间距。
android VLayout 全面解析

文章图片

对于LinearLayoutHelper, 调用
public void setDividerHeight(int dividerHeight)

weights
ColumnLayoutHelper, GridLayoutHelper的属性, 它们都是提供网格状的布局能力, 建议使用GridLayoutHelper, 它的能力更加强大, 参考下文介绍。默认情况下, 每个网格中每一列的宽度是一样的, 通过weights属性, 可以指定让每一列的宽度成比例分配, 就像LinearLayout的weight属性一样。 weights属性是一个float数组, 每一项代表某一列占父容器宽度的百分比, 总和建议是100, 否则布局会超出容器宽度; 如果布局中有4列, 那么weights的长度也应该是4; 长度大于4, 多出的部分不参与宽度计算; 如果小于4, 不足的部分默认平分剩余的空间。
android VLayout 全面解析

文章图片

对于ColumnLayoutHelper, GridLayoutHelper, 调用
public void setWeights(float[] weights)

vGap, hGap
GridLayoutHelper与StaggeredGridLayoutHelper都有这两个属性, 分别控制视图之间的垂直间距和水平间距。
android VLayout 全面解析

文章图片

对于GridLayoutHelper, StaggeredGridLayoutHelper, 调用
public void setHGap(int hGap)public void setVGap(int vGap)

spanCount, spanSizeLookup
GridLayoutHelper的属性, 参考于系统的GridLayoutManager, spanCount表示网格的列数, 默认情况下每一个视图都占用一个网格区域, 但通过提供自定义的spanSizeLookUp, 可以指定某个位置的视图占用多个网格区域。
android VLayout 全面解析

文章图片

使用spanCount调用
public void setSpanCount(int spanCount)

使用spanSizeLookup
public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup)

autoExpand
GridLayoutHelper的属性, 当一行里视图的个数少于spanCount值的时候, 如果autoExpand为true, 视图的总宽度会填满可用区域; 否则会在屏幕上留空白区域。
android VLayout 全面解析

文章图片

接口:
public void setAutoExpand(boolean isAutoExpand)

lane
StaggeredGridLayoutHelper中有这个属性, 与GridLayoutHelper里的spanCount类似, 控制瀑布流的列数。
接口:
public void setLane(int lane)

fixAreaAdjuster
【android VLayout 全面解析】fix类型的LayoutHelper, 在可能需要设置一个相对父容器四个边的偏移量, 比如整个页面里有一个固定的标题栏添加在vlayout容器上, vlayout内部的fix类型视图不希望与外部的标题有所重叠, 那么就可以设置一个fixAreaAdjuster来做偏移。
android VLayout 全面解析

文章图片

接口:
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是视图底边相对父容器的下边距偏移量;
android VLayout 全面解析

文章图片

设置基准调用
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: 默认不显示视图, 当页面滚出这个视图的位置的时候显示;
    android VLayout 全面解析

    文章图片
接口:
public void setShowType(int showType)

stickyStart, offset
StickyLayoutHelper的属性, 当视图的位置在屏幕范围内时, 视图会随页面滚动而滚动; 当视图的位置滑出屏幕时, StickyLayoutHelper会将视图固定在顶部( stickyStart = true) 或者底部( stickyStart = false) , 固定的位置支持设置偏移量offset。
android VLayout 全面解析

文章图片

接口:
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); } }

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
android VLayout 全面解析

文章图片

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 + " " ); }

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
android VLayout 全面解析

文章图片

ScrollFixLayoutHelper
同上, 代码是差不多的, 不过官方所说的标签, 置顶等功能。并不能实现。官方demo也并没有实现此功能。虽然我们可以通过点击图片来进行置顶。但是具体功能感觉和fixlayout无异。文末有demo。博友们自己下载试试就知道了。
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);

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
android VLayout 全面解析

文章图片

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);

效果图:
顶部:
android VLayout 全面解析

文章图片

实体和顶部合二为一:
android VLayout 全面解析

文章图片

总结 对于这个开源, 我的总结就是, 每个开源都有它的强大之处, 至于我们会不会发现就看我们如何去理解了。而且这个开源可以多个LayoutHelper进行结合, 比之前那些LinearLayoutmanager、 Gridlayoutmanager之类的强大太多。我感觉有了这个。我之前那个SWPullRecyclerLayout可以在精炼, 进行多方面布局的结合来使用。现在, 我们已经学会如何使用它的。之后我想我们就应该试着去看它的源码来了解它是如何实现的。因为我看了下源码, 这个开源15年就开始做的。我记得recyclerview也是15年4月才发布出来。可想而知, 阿狸团队的强大。
demo的源码我已上传到csdn: 点击下载demo
github: https://github.com/sw950729/VLayout

    推荐阅读