写点什么

Gbox 开源:比 RN 和 WebView 更轻的高性能动态化业务容器,解决首页动态化的痛点

用户头像
Android架构
关注
发布于: 21 分钟前

原理其实很简单,也许你都已经猜到了。mock 模块打开了一个 http 服务器,overview 扫码拿到的是电脑的 ip 地址和端口号,然后 overview 每隔一秒去请求服务器下发布局和数据,这样就可完成布局的实时预览。附上源码??[MockSession.kt](


)。

5 开始编写布局文件

5.1 绑定表达式

在开始编写布局之前我们需要了解 Gbox 的绑定表达式。


Gbox 的绑定表达式是基于嵌入式 Tomcat(对!就是用在 Spring Boot 上那个)所使用的 EL 表达式类库开发的,所以它支持 EL 表达式的所有特性,包括 Java Bean 访问、方法调用、三元表达式、数学运算等的。


假如你有一个像下面一样的 json:


{"number":1000,"control":{"display":true},"text":"这段文字不会被显示"}


编写下面的绑定表达式


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><TexttextSize="30"text="${control.display?'其他文本':text}"height="100"></Text></Flex>


这个 Text 将不会显示文本'这段文字不会被显示',而会显示'其他文本'。值得注意的是在绑定表达式中字符串常量使用单引号包裹。


![](https://user-gold-cdn.xitu.


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


io/2019/11/7/16e448837b9f3c2c?imageView2/0/w/1280/h/960/ignore-error/1)


数学运算:


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><TexttextSize="30"text="${number+1000}"height="100"></Text></Flex>


不止是 text 属性,你还可以在任意属性中使用绑定表达式,以满足你数据展示的需要。


5.2 Flex

由于 Gbox 是基于 Litho 的 UI 框架,而 Litho 又是使用 yoga 这个基于 flexbox 布局模型的布局引擎的,所以首先要支持的就是 Flex,顾名思义,就是弹性容器。


Flex 的实现非常简单,你可以理解为增强版的 LinenerLayout,它支持以下属性:


首先是 flexDirection,它用来指定主轴方向,支持 row、column、rowReverse、columnReverse 四种排布方式,下面是 row 和 column 的截图,没有填写 flexDirection 时则默认为 row。


<?xml version="1.0" encoding="utf-8"?><Flex flexDirection="row"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex>



<?xml version="1.0" encoding="utf-8"?><Flex flexDirection="column"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex>



接下来是 justifyContent 属性,它标识了其所有子 Layout 在主轴上的对齐方式,包含 flexStart、flexEnd、center、spaceBetween、spaceAround 五种,下面我通过编写一个 xml,展示了该效果。


flexStart、flexEnd、center 无需多言,而 spaceBetween、spaceAround 需要解释一下。


  • spaceBetween 是指两端对齐,项目之间的间隔都相等。

  • spaceAround 是指每个项目两侧的间隔相等。


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="column"><FlexjustifyContent="flexStart"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><FlexjustifyContent="flexEnd"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><FlexjustifyContent="center"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><FlexjustifyContent="spaceBetween"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><FlexjustifyContent="spaceAround"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex></Flex>



屏幕太小,一张截图截不完。



然后是 alignItems,它描述的的子 Layout 在副轴上的对齐方式,支持 flexStart、flexEnd、center、baseline、stretch 五种。


其中 baseline 表示与项目的第一行文字的基线对齐,stretch 指定时,如果子 Layout 未指定高度,则会占满父 Layout。


编写下面的 xml:


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"height="360"background="yellow"flexDirection="row"><Flexheight="360"alignItems="flexStart"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><Flexheight="360"alignItems="flexEnd"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><Flexheight="360"alignItems="center"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><Flexheight="360"alignItems="baseline"margin="5"><Flexbackground="red"width="100"height="100"></Flex><Flexbackground="blue"width="100"height="100"></Flex></Flex><Flexheight="360"alignItems="stretch"margin="5"><Flexbackground="red"width="100"></Flex><Flexbackground="blue"width="100"></Flex></Flex></Flex>



在上面的布局中,你会发现 360 这个值会经常出现,没错,在 Gbox 中它是一个特殊值。为了做屏幕适配,Gbox 的大小单位是设备独立的,它以屏幕宽度作为基准,将屏幕宽度分为 360 份,一个单位的像素值=屏幕宽度像素值/360,这也刚好是 2x 设计图纸的大小,相信你们的 UI 设计师会喜欢 Gbox 的。


Gbox 的所有布局属性和层级,最终将被应用到 facebook 的 yoga 布局引擎中去,无论布局有多复杂您都不需要担心,因为所有的计算都是在可指定的 Layout 线程中进行的,根本不会影响主线程,并且最终生成在屏幕上的 View 是没有这些冗余布局层级的。有关更多 Litho 的信息,建议您查阅[Litho 的相关文档](


)。

5.3 Frame

Frame 实现了类似 Android 上 FrameLayout 的布局效果,用于实现 Flex 难以实现的多层叠加效果。


在 Frame 上,Gbox 采用了比 Flex 更激进的布局测量策略。我们都知道,在 Android 的 FrameLayout 中 onMeasure 会去测量所有的子 Layout,最终才能确定宽高,Gbox 中利用 Litho 的 Component 的不可变性(线程安全),将这一操作进行了并行化。



Frame 拥有独立的线程池,可以并发地测量所有地子 Layout,最终的结果在一个线程汇集,下图演示了该过程。



PS: 说人话就是调用了java.util.concurrent.Executors#newCachedThreadPool,然后等待在一个线程等待其他java.util.concurrent.Future完成,源码链接??[FrameFactory.kt](


)


编写下面的布局实现叠加效果:


<?xml version="1.0" encoding="utf-8"?><Framewidth="360"height="360"background="yellow"flexDirection="row"><Flexbackground="red"width="100"height="100"></Flex><FlexmarginTop="50"marginLeft="50"background="blue"width="100"height="100"></Flex></Frame>


5.4 Image

Image 不仅仅只是一张简单的 ImageView,它封装了 Glide 图片加载引擎,支持异步加载、圆角裁剪和高斯模糊。


使用 url 来加载网络图片:


Gbox 没有使用 Litho 的 State 来实现异步图片加载,所以不会触发 Litho 的布局更新,而是直接替换底层的 Drawble,然后调用 invalidateDrawable,刷新脏矩形。


PS: 说人话就是使用了[DrawableWrapper.kt](


) 。


mock 所使用的 json 数据:


{"image2": "http://5b0988e595225.cdn.sohucs.com/images/20180606/0a49d21848324503a1e04c4b942a1631.png"}


编写 xml:


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><Imagewidth="360"height="360"url="${image2}"></Image></Flex>



borderRadius 存在时,内部的图片会被裁剪:


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><ImagescaleType="fitXY"borderRadius="100"width="360"height="360"url="${image2}"></Image></Flex>



使用 blurRadius 和 blurSampling 控制高斯模糊:


blurRadius 为弧度,值在 1-25 之间,blurSampling 为采样率,值要比 1 大。


Gbox 使用 renderscript 技术将高斯模糊的效率最大化,能够减少使用高斯模糊时图片出现的延迟时间。


PS: 说人话就是在 Glide 加载图片的时候加了个Transformation,源码链接??[BlurTransformation.kt](


)



<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><ImageblurRadius="25"blurSampling="2"scaleType="fitXY"borderRadius="100"width="360"height="360"url="${image2}"></Image></Flex>



与 ImageView 一样支持 scaleType:


细心的朋友会发现,其实上面已经在使用 fitXY 了,笑~


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><ImagescaleType="fitEnd"width="360"height="360"url="${image2}"></Image></Flex>


5.5 Text

Text 用于显示文本,目前支持一下属性修饰:


  • text 用于指定要显示的文本

  • horizontalGravity 用于指定文本对齐方式,支持 center、left、right

  • textSize 用于指定文本大小

  • textStyle 用于指定文本风格如 normal(默认)、bold(粗体)

  • maxLines 指定最大行数

  • minLines 指定最小行数

  • textColor 指定字体颜色


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="column"><TexttextColor="#59a9ff"textSize="30"text="文本 1111"></Text><TexttextColor="red"textSize="30"text="文本 1111"></Text><TexttextColor="blue"textSize="30"text="文本 1111"></Text></Flex>


5.6 Native

Gbox 对传统业务组件也是友好的。


如果将 Gbox 接入以后之前写的自定义 View 都得从头编写的话,那 Gbox 就失去了快速开发的意义了。所以 Gbox 也支持原生 View 的接入。


PS: 说人话就是封装了com.facebook.litho.ViewCompatComponent,源码??[NativeFactory.kt](


)。


使用 type 属性,编写下面的代码,就能实现下图中所展示的样式。


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="row"><FlexflexDirection="row"><TextmarginLeft="10"textSize="28"text="开关"></Text><NativemarginLeft="10"type="ch.ielse.view.SwitchView"></Native></Flex></Flex>



值得注意的是 Native 已经是布局树的叶子节点,这意味着不支持再使用 Native 包裹其他节点。

5.7 Scroller

Scroller 就是 ScrollView,与 ScrollView 一样,它只能有一个子 View,它由两个属性控制样式:


  • scrollBarEnable 是一个布尔值(true 或者 false)控制是否显示滚动条。

  • orientation 控制横向还是竖向(vertical 或者 horizontal)。


<?xml version="1.0" encoding="utf-8"?><Scroller><Flex><Imagewidth="360"height="600"scaleType="fitXY"url="${image2}"></Image></Flex></Scroller>


【这...这就不展示了吧...我实在是觉得这玩意截图没啥意义...】

5.8 for

当 model 数据中有列表数据需要展开时,就需要用到 for 标签。


for 标签有三个属性,在使用时都是必须指定的,分别是 var,from,to,index 用于指定循环中迭代器的名字,from 和 to 则指定了 var 的的迭代范围。 比如你有下面的数据:


{"height":1000,"itemTexts":["Gbox","Facebook","Litho","Google"]}


编写下面的布局:


<?xml version="1.0" encoding="utf-8"?><Flexwidth="360"background="yellow"flexDirection="column"><for var="index" from="1" to="3"><TexttextSize="30"text="${itemTexts[index]}"></Text></for></Flex>


可以被等价展开成:


<Flexwidth="360"background="yellow"flexDirection="column"><TexttextSize="30"text="{itemTexts[2]}"></Text><TexttextSize="30"text="${itemTexts[3]}"></Text></Flex>



for 标签 var 所指定的迭代器只会在 for 循环所包括的布局标签中生效


PS: for 标签是调用了 Tomcat EL 的ELContext#enterLambdaScopeELContext#exitLambdaScope实现的,代码我就不在这里贴了,你可以??直接[跳转到 github 看源码](


)

5.9 内置函数

目前 Gbox 还支持一些内置函数,内置函数必须在绑定表达式中才能调用:


utils:check(o:Any)


可以检测一个变量是否有效,为空或者大小为 0 的集合或者为空的字符串都会返回 false 值


check 方法是由 kotlin 实现的:


fun check(o: Any?): Boolean {return when (o) {is String -> o.isNotEmpty()is Collection<*> -> !o.isEmpty()is Number -> o.toInt() != 0else -> o != null}}


在下面的布局逻辑中,屏幕上不会展示任何东西,因为 json 中没有'no_found'这个变量。


<?xml version="1.0" encoding="utf-8"?><Flex><Imagewidth="360"height="360"url="${utils:check(no_found)?image2:''}"></Image></Flex>


draw:gradient(o:Orientation,vararg colors: String)

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Gbox开源:比RN和WebView更轻的高性能动态化业务容器,解决首页动态化的痛点