1 我们要解决什么问题?
在线上对于某些适用于要求强展示、轻交互、随时上线场景,RN和WebView显得不够灵活,性能表现也不够好。例如首页feed流卡片,一级页面的活动页等,这些页面也往往只是需要局部动态化。
对于这些情况,美团APP团队有自己的一套闭源的动态化容器MTFlexbox来应对这些情况,让布局快速开发上线,之前在美团实习期间有幸学习过MTFlexbox,这里我要感谢一下美团APP终端业务研发组的同学们,感谢我的Leader,没有他们的帮助就没有现在的我。
在实习结束返校之后,一直想个自己的实习做一个学习总结,但又不知道以什么为主题比较合适。自己对MTFlexbox理解得以及其适用的业务特点理解的还算深刻,所以最终我选择了尝试自己去设计实现一个与MTFlexbox功能类似的开源框架Gbox。
Gbox使用apache开源协议,不使用MTFlexbox的任何源代码,也不是MTFlexbox的兼容版本,它是一个完全基于开源软件实现的全新开源软件,并且Gbox使用kotlin编码。
Gbox花了自己很多心血,从设计到技术选型再到编码完成,花了我大半个月的时间,踩了好多litho、Drawable、Canvas的坑之后,现在Gbox已经基本可用了(从版本号0.1.1开始)。
2 实现效果
Gbox有丰富的样式能力,能够实现圆角、高斯模糊、渐变色、文本、网络图片的绘制,并且得益于facebook开源的litho,绝大部分工作可以在异步线程进行,大大减轻了主线程的负担。
同时,得益于强大的apache el(使用在嵌入式tomcat上的版本),使得Gbox样式模板xml中的所有属性均支持表达式解析,包括函数调用、算数运算、三元表达式、java bean访问,同时Gbox还支持for语句。
1.1 对比截图
对比美团首页线上方案MTFlexbox,左为MTFlexbox(美团APP),右为Gbox(Gbox的实时预览APP)。
1.2 样式数据
<?xml version="1.0" encoding="utf-8"?>
<Flex
background="WHITE"
borderRadius="12"
flexDirection="column"
width="300">
<Flex
alignItems="center"
marginLeft="10"
marginTop="12"
flexDirection="row">
<Text
textStyle="bold"
textSize="16"
text="碧蓝航线电子科大店">
</Text>
<Text
marginTop="2"
paddingLeft="4"
paddingRight="4"
background="${draw:gradient(l2r,'#EE9611','#F7C709')}"
borderRadius="3"
marginLeft="12"
text="外卖"
textSize="10"/>
</Flex>
<Flex
marginLeft="10"
marginTop="5"
flexDirection="row">
<Text
textColor="#E6941A"
textSize="11"
text="4.1分">
</Text>
<Text
textColor="#808080"
textSize="11"
text=" | 月售929">
</Text>
<Text
textColor="#808080"
textSize="11"
text=" | 配送¥0">
</Text>
<Flex
flexGrow="1">
</Flex>
<Text
textColor="#808080"
marginLeft="10"
marginRight="10"
textSize="11"
text="31分钟送达">
</Text>
</Flex>
<Flex
alignItems="center"
marginLeft="10"
marginTop="5">
<Text
borderRadius="3"
paddingLeft="4"
paddingRight="4"
textSize="10"
background="${draw:gradient(l2r,'#F70909','#FF6600')}"
textColor="WHITE"
text="优惠">
</Text>
<Text
textColor="#808080"
marginLeft="5"
textSize="12"
text="首单减12">
</Text>
</Flex>
<Flex
height="100"
flexGrow="1"
marginBottom="10"
marginLeft="7"
marginRight="7"
marginTop="8"
flexDirection="row">
<Flex
flexDirection="column"
justifyContent="center"
marginLeft="3"
marginRight="3"
flexGrow="1">
<Image
borderRadius="4"
scaleType="fitXY"
flexGrow="1"
url="${image2}">
</Image>
<Text
marginTop="5"
textAlign="center"
textSize="11"
text="拉菲">
</Text>
</Flex>
<Flex
flexDirection="column"
justifyContent="center"
marginLeft="3"
marginRight="3"
flexGrow="1">
<Image
borderRadius="4"
scaleType="fitXY"
flexGrow="1"
url="${image1}">
</Image>
<Text
marginTop="5"
textAlign="center"
textSize="11"
text="初音未来">
</Text>
</Flex>
<Flex
flexDirection="column"
justifyContent="center"
marginLeft="3"
marginRight="3"
flexGrow="1">
<Image
blurSampling="3"
blurRadius="25"
borderRadius="4"
scaleType="fitXY"
flexGrow="1"
url="${image2}">
</Image>
<Text
marginTop="5"
textAlign="center"
textSize="11"
text="高斯模糊">
</Text>
</Flex>
</Flex>
</Flex>
复制代码
1.3 数据
{
"image1": "https://uploadfile.bizhizu.cn/2014/1127/20141127031018144.jpg",
"isEmpty": 1,
"name": "tttt",
"bofang": "100万",
"bofangSize": 10,
"danmu": "10万",
"gengduo": "https://s2.ax1x.com/2019/10/11/uqo5tJ.png",
"image2": "http://5b0988e595225.cdn.sohucs.com/images/20180606/0a49d21848324503a1e04c4b942a1631.png"
}
复制代码
3 Gbox的特性
Gbox是对业务以及性能友好的
- 它基于facebook开源的litho,异步计算布局,解放主线程,并且直接使用Drawable进行渲染,消除View层级,与WebView相比有更大的性能优势
- 使用Glide作为图片加载引擎,所有图片均可以从网络异步加载,异步图片的加载不会触发litho的视图树的状态更新
- 前后端分离,后端下发布局+数据的json,可集成在数据接口下发,本地自主解析渲染布局
- 单View接入,基本无入侵性,可用于替换现有的任意一个静态展示型的View,并支持曝光埋点、点击埋点、点击时间处理等事件
- 提供完整的开发工具链,包括布局实时预览APP(overview),以及mock工具,可通过扫码链接电脑进行实时预览调试
- 基于flexbox布局模型,并且包含丰富的可配置样式,边框,边框颜色,圆角,图片,文本等
- 强大的表达式解析功能,包括数学运算,for语句,三元表达式,简单的java方法调用,使用表达式时需使用'${}'包围
- 布局自适应,布局使用的单位为是设备独立的pt,以设备屏幕宽度为准,1pt=(设备屏幕宽度像素值/360)像素
- 使用kotlin编码,代码实现非常简洁,很适合阅读学习
- 支持原生View嵌入Gbox
4 丰富的样式支持
4.1 通用样式
布局支持多种样式,但有一些样式是通用的
- background 可以是颜色以#开头或是颜色的名字,或者为url,还可以使用渐变色,调用内置函数“fn:gradient”实现渐变色,最后一个参数是可变参数,如下:
<?xml version="1.0" encoding="utf-8"?>
<Flex
width="360"
height="600"
borderWidth="20"
borderRadius="30"
borderColor="red"
background="${fn:gradient(t2b,red,blue)}">
</Flex>
复制代码
- borderRadius 圆角弧度
- borderWidth 边框宽度
- borderColor 边框颜色
- alignSelf 支持flexStart,flexEnd,center,baseline,stretch
- height 高
- width 宽
- margin 外边距
- marginBottom 外边距
- marginTop 外边距
- marginLeft 外边距
- marginRight 外边距
- padding 内边距
- paddingTop 内边距
- paddingBottom 内边距
- paddingLeft 内边距
- paddingRight 内边距
- clickUrl 一个url,可触发EventListener的回调
- reportClick 点击时上报一个json,此json支持数据绑定,可触发EventListener的回调
- reportView 曝光时上报一个json,此json支持数据绑定,可触发EventListener的回调
4.2 Image
使用Glide作为图片加载引擎,支持异步加载、高斯模糊(使用高效的renderscript)、圆角裁剪
- url 图片来源,一个url
- blurRadius 高斯模糊的半径,最大为25
- blurSampling 高斯模糊的采样率,默认为1
- borderRadius 有圆角弧度时,会裁剪内部
- scaleType 缩放类型,有center,fltXY,fitCenter,fitStart,fitEnd,centerInside
4.3 Text
用于显示文本
- text 显示文本
- textAlign 文本对齐,支持center,left,right
- textSize 文本大小
- textStyle 文本风格,支持normal,bold
- maxLines 最大行数
- minLines 最小行数
- textColor 字体颜色
4.4 Flex
flex风格的布局容器
- flexDirection 支持row,rowReverse,column,columnReverse
- flexWrap 容器是否包住内部,支持noWrap,wrap,wrapReverse
- justifyContent 主轴对齐,支持flexStart,flexEnd,center,spaceBetween,spaceAround
- alignItems 副轴对齐,支持flexStart,flexEnd,center,baseline,stretch
- alignContent 支持flexStart,flexEnd,center,baseline,stretch
4.5 Scroller
滑动列表实现,与ScrollerView等价
- scrollBarEnable 启用或关闭scrollBar
- orientation 水平或者垂直(vertical,horizontal)
4.6 Frame
与FrameLayout类似,可实现多层级叠加
4.7 Embedded
可在布局中嵌入传统View
- type 类名
4.8 for
逻辑标签,将内部的标签展开成多组,三个字段都是必填的
- name 循环中所使用的迭代变量
- from 开始的下标
- to 结束的下标
<?xml version="1.0" encoding="utf-8"?>
<Flex
height="${height}" >
<for name="index" from="1" to="3">
<Text
text="${itemTexts[index]}"
height="100">
</Text>
</for>
</Flex>
复制代码
等价展开
<?xml version="1.0" encoding="utf-8"?>
<Flex
height="${height}" >
<Text
text="${itemTexts[1]}"
height="100">
</Text>
<Text
text="${itemTexts[2]}"
height="100">
</Text>
<Text
text="${itemTexts[3]}"
height="100">
</Text>
</Flex>
复制代码
4.8 辅助函数
可以在表达式中调用
- utils:check(o:Any)可以检擦一个变量是否有效,为空或者大小为0的集合或者为空的字符串都会返回false值
- draw:gradient(o:Orientation,vararg colors: String) 用于实现渐变色,第一个参数为渐变色的方向,有t2b,tr2bl,l2r,br2tl,b2t,r2l,tl2br八种方向可选,第二个参数是可变参,可传入若干个颜色的字符串
5 运行测试用例
- 在手机上安装overview
- 确保手机与电脑在同一网络环境下
- 运行mock模块下test文件夹下的MockTestCase(mac上路径可能会出点问题)
- 用overview扫描控制台出现的二维码,即可开始测试
- Ctrl+S保存后会刷新手机上的布局(开启LiveReload时)
- 您可参照mock模块与overview模块进行快速集成
6 获取Gbox
6.1 在github上clone源码
6.2 利用jitpack集成
//Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
//Add the dependency
dependencies {
implementation 'com.github.LukeXeon.flexbox:core:Tag'
}
复制代码
7 项目中所使用的开源框架
7.1 mock
- google zxing 二维码
- google gson json解析
7.2 core
- apache el 数据绑定
- facebook litho 渲染
7.3 overview
- squareup retrofit2 网络请求
- didi DoraemonKit 辅助工具
8 结语
iOS侧和更多功能已经在开发计划中,敬请关注,也欢迎你来贡献,我们将一起开源共建,做出最好的Gbox。
最后的最后还是惯例啦,如果喜欢我的文章别忘了给我点个赞,拜托了这对我来说真的很重要。如果你觉得东西对你有用GitHub也帮点个star吧。