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

编写下面的绑定表达式

<?xml version="1.0" encoding="utf-8"?>




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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数学运算:

<?xml version="1.0" encoding="utf-8"?>




不止是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"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

  • spaceBetween是指两端对齐,项目之间的间隔都相等。
  • spaceAround是指每个项目两侧的间隔相等。
<?xml version="1.0" encoding="utf-8"?>
































外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

编写下面的xml:

<?xml version="1.0" encoding="utf-8"?>
































外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在上面的布局中,你会发现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"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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"?>




外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

<?xml version="1.0" encoding="utf-8"?>




外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

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

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

<?xml version="1.0" encoding="utf-8"?>




外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与ImageView一样支持scaleType:

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

<?xml version="1.0" encoding="utf-8"?>




外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.5 Text

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

  • text用于指定要显示的文本
  • horizontalGravity用于指定文本对齐方式,支持center、left、right
  • textSize用于指定文本大小
  • textStyle用于指定文本风格如normal(默认)、bold(粗体)
  • maxLines指定最大行数
  • minLines指定最小行数
  • textColor指定字体颜色
<?xml version="1.0" encoding="utf-8"?>








外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.6 Native

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

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

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

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

<?xml version="1.0" encoding="utf-8"?>








外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

5.7 Scroller

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

  • scrollBarEnable是一个布尔值(true或者false)控制是否显示滚动条。
  • orientation控制横向还是竖向(vertical或者horizontal)。
<?xml version="1.0" encoding="utf-8"?>

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

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"?>






可以被等价展开成:








外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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() != 0
else -> o != null
}
}

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

<?xml version="1.0" encoding="utf-8"?>

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

用于实现渐变色,第一个参数为渐变色的方向,有t2b(上到下),tr2bl(上右到下左),l2r(右到左),br2tl(下右到上左),b2t(下到上),r2l(右到左),tl2br(上左到下右)八种方向可选,第二个参数是可变参,可传入若干个颜色的字符串

kotlin的源码实现:

fun gradient(orientation: GradientDrawable.Orientation, vararg colors: String): GradientDrawable {
return GradientDrawable(orientation, colors.map {
parseColor(it)
}.toIntArray())
}

编写xml实现渐变色:

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.10 其他通用属性

除了上述属性之外还有很多属性是通用的,受限于篇幅,这里我对一些比较重要的属性进行简单介绍。

background属性是对所有Widget都通用的,用于为图片指定背景,它支持以下三种显示来源:

  • 图片的url
  • 以#开头的十六进制颜色值
  • 渐变色(上面已经演示过了)

以图片url为背景

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

borderRadius 用于实现裁剪背景边界的圆角。

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你还可以使用borderColorborderWidth为边界指定宽度和颜色。

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用clickUrl并打开overview APP的控制台,点击图片,就能在EventListener中收到点击事件传递下来的信息,它可以是一个url,供外部跳转使用。

<?xml version="1.0" encoding="utf-8"?>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

于此类似的属性还有reportView(曝光时上报),reportClick(点击时上报)都可以在控制台查看。

还有一些通用属性,我也在这里也简单列了一下:

宽高

  • height
  • width

可见性

  • visibility 与Android类似,支持visible、invisible和gone

外边距

  • margin
  • marginBottom
  • marginTop
  • marginLeft
  • marginRight

内边距

  • padding
  • paddingTop
  • paddingBottom
  • paddingLeft
  • paddingRight

Flexbox所支持的其他属性

  • alignSelf
  • alignContent
  • flexGrow
  • flexShrink

对于Flexbox这部分,我真诚地推荐你去看阮一峰老师的文章Flex布局教程

Gbox中的对应属性基本上就是将这些属性使用java的命名风格,取消中位线,第二个单词开始使用大写。如在css中的align-content在Gbox中就是alignContent

6 后端集成注意事项

6.1 集成建议

在后端,可能集成者需要建立一个统一的布局管理系统,包括:

  • 布局cdn。
  • git联动的版本控制功能等等。

当然这些也在未来的开发计划中,欢迎您的PR。

6.2 下发的是json不是xml

值得注意的是,虽然编写布局使用的是xml,但是您可以发现最终mock服务器下发到客户端的只有json,这是因为在下发布局时mock服务器已经将xml转换为了json,这样做的目的是为了布局集成到数据接口中下发,使用统一工具进行解析,所以Gbox没有耦合xml的解析模块,而是最大化的利用了现有基础设施。所以在后端集成时需要把xml转换为json来保存。

7 在新项目中集成Gbox

7.1 远程依赖Gbox

Gbox使用jitpack进行构建,在你的根项目的build.gradle中添加

allprojects {
repositories {

maven { url ‘https://jitpack.io’ }
}
}

然后在模块中依赖

dependencies {
implementation ‘com.github.LukeXeon.flexbox:core:latest.release’
}

Sync项目,即可将SDK集成到项目中,Gbox的包大小不算太大,约为1M左右,这其中主要是Facebook的Litho的大小。

7.2 集成Gbox的容器Litho

Gbox基于Litho,所以你还得先找个地方初始化Litho,可以是Application,或者第一个Activity里,反正用LithoView之前初始化就行了。

SoLoader.init(this, false);

LithoView是Gbox的容器,在xml中使用:

<com.facebook.litho.LithoView
android:id=“@+id/host”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
</com.facebook.litho.LithoView>

然后在Java层中拿到实例,调用setComponentAsync方法,传入一个新构造的DynamicBox。

mLithoView.setComponentAsync(
DynamicBox.create©
.bind(data)
.layout(layout)
.eventListener(this)
.build()
);

其中layout是一个com.guet.flexbox.NodeInfo类的实例,它用来描述一颗布局树,是整棵布局树的树根。

而data则是绑定到布局中的数据,它支持多种数据格式自动匹配,分为以下两种情况:

  • 在项目中依赖了Gson的情况下,data可以直接是String、byte[]、Reader、InputStream这些数据源。
  • 如果项目中没有Gson,那么Gbox也支持嵌套的多层级Map<String,Object>以及标准的java bean(有getter,setter)作为数据源。

在overview APP中,我使用了Retrofit来简化了这一过程。

添加Retrofit的依赖:

implementation ‘com.squareup.retrofit2:retrofit:2.6.2’
implementation ‘com.squareup.retrofit2:converter-gson:2.6.2’

用Retrofit实例化接口:

package com.guet.flexbox.overview;
o.LithoView
android:id=“@+id/host”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
</com.facebook.litho.LithoView>

然后在Java层中拿到实例,调用setComponentAsync方法,传入一个新构造的DynamicBox。

mLithoView.setComponentAsync(
DynamicBox.create©
.bind(data)
.layout(layout)
.eventListener(this)
.build()
);

其中layout是一个com.guet.flexbox.NodeInfo类的实例,它用来描述一颗布局树,是整棵布局树的树根。

而data则是绑定到布局中的数据,它支持多种数据格式自动匹配,分为以下两种情况:

  • 在项目中依赖了Gson的情况下,data可以直接是String、byte[]、Reader、InputStream这些数据源。
  • 如果项目中没有Gson,那么Gbox也支持嵌套的多层级Map<String,Object>以及标准的java bean(有getter,setter)作为数据源。

在overview APP中,我使用了Retrofit来简化了这一过程。

添加Retrofit的依赖:

implementation ‘com.squareup.retrofit2:retrofit:2.6.2’
implementation ‘com.squareup.retrofit2:converter-gson:2.6.2’

用Retrofit实例化接口:

package com.guet.flexbox.overview;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值