近几年跨平台动态化方案盛行,从最初的Hybrid到FaceBook出品的RN和阿里出品的Weex再到Google出品的Flutter。可以看出大厂也在不断探索更快速更高效的开放模式,毕竟技术为项目服务,项目为用户服务。只有更高效的迭代方式,才能尽可能的去提升用户体验。
目前58app的首页,详情页均可以理解为弱的跨端动态化技术,双端都支持相同的协议,根据不同的协议作出不同的UI展示和逻辑处理。而tangram实现了较强的动态化技术,及更有灵活性。可以减少发版次数。
Tangram的动态化技术并不像RN WEEX Flutter那样做到完全的动态化,Tangram更关注的是界面动态化,性能。下面我们来揭开Tangram的面纱。

布局灵活性

Tangream布局的灵活性是依赖阿里开源Vlayout实现的。通过重写Recyclerview的LayoutManger实现自定义灵活布局。首先我们需要理解Tangram模型

在Tangram框架中界面由卡片(Card) 和 组件(Item)构成。卡片负责布局组件,Tangram框架内置了很多Card样式。(Tangram2.0更新,对Tangram模型进行了重新的定义,从原来的『卡片』+『组件』升级成『布局』+『组件』,即原来的『卡片』认为是一种具有布局能力的组件,具备嵌套另一组件的能力)
目前卡片(布局)支持的样式如下:
流式(网格)布局(container-oneColumn),一拖N布局(container-onePlusN),浮动布局固定布局(container-float),吸顶布局(container-sticky),瀑布流布局(container-waterfall)等。具体可以参考内置布局支持
当产品提出想更改布局样式的时候只需更改协议的type即可,总会有一种满足他。

{
"type": "container-oneColumn", ---> 描述布局类型
"style": { ---> 描述样式
  ...
},
"header": { ---> 描述header
},
"items": [ ---> 描述组件列表
  ...
],
"footer": { ---> 描述footer
}
}

基于以上Tangram做到了布局灵活性的目的。

动态组件(VirtualView)

上面提到了卡片(布局),下面介绍一下卡片操作的对象组件。Tangram框架中将组件分为原生组件和动态组件。原生组件可以理解同我们日常开发首页item一样将编写ViewHolder然后根据type进行注册。这里重点说一下动态组件,动态组件是Tangram动态化的另一重要体现。
动态组件(VirtualView)是阿里推出的组件动态更新解决方案,解决APP native页面更新样式时,需要发版处理。适合经常做运营推广的页面。

VirtualView使用流程

可以看出VirtualView的整体框架View模板与数据分离,先下发模板布局,在下发数据进行模板填充。

模板文件编写

VirtualView框架内置了一些基础原子控件(NText,VText,NImage,NLine,VLine...)和基础容器控件(FrameLayout,GridLayout,VHLayout,NFrameLayout,NGridLayout,NVHLayout...)。我们可以使用这些提供的控件去编写我们的XML布局文件。(可以看到控件的命名规则是以N和V开始,有什么区别呢?)
布局xml编写栗子

<FrameLayout
        layoutWidth="340rp"
        layoutHeight="wrap_content"
        action="action"
        flag="flag_exposure|flag_clickable"
        background="#FFFFFF"
        autoDimDirection="X"
        autoDimX="340"
        autoDimY="240"
        >
		<NText 
         text="${title}"
         textSize="12"
         textColor="#999999"
         maxLines="1"
         layoutGravity="left|v_center"
         layoutWidth="match_parent"
         layoutHeight="wrap_content"
         gravity="left" />		
				
    <NImage
            scaleType="fit_xy"
            layoutWidth="212.5rp"
            layoutHeight="28.5rp"
            layoutMarginTop="29rp"
						flag="flag_exposure|flag_clickable"
            layoutMarginLeft="30rp"
            layoutGravity="top|left"
            src="${imgUrl}"/>
 
</FrameLayout>
  1. 如何在布局文件中绑定数据?
    与DataBinding思想一致,通过EL表达式访问数据字段 如 ${title} ,同时数据绑定支持三元运算符如 @{${logoUrl} ? visible : invisible }

  2. 事件声明
    默认情况下组件是不触发事件的,只有在模板里显示地声明了才具备触发能力。事件声明属性字段是 flag,其值可以通过 | 组合一次性声明多个。如 flag="flag_exposure|flag_clickable"

  3. 事件处理
    上面我们提出了Tangram是面向界面的动态化,server下发的也是布局模板。所以Tangram不像RN,Weex,Fultter那样可以编写业务逻辑,Tangram的事件处理需要端去内置处理。

	 VafContext vafContext = tangramEngine.getService(VafContext.class);
vafContext.getEventManager().register(EventManager.TYPE_Click, new IEventProcessor() {

    @Override
    public boolean process(EventData data) {
        //handle here
        return true;
    }
});
vafContext.getEventManager().register(EventManager.TYPE_Exposure, new IEventProcessor() {

    @Override
    public boolean process(EventData data) {
        //handle here
        return true;
    }
});

协议数据填充

 {
       "type":"detail"
        "imgUrl": "https://pic1.58cdn.com.cn/anjuke_58/c488d6dc6cd6263246bf1a07b6575def", 
        "title": "\u65b0\u534e\u533a\u4e1c\u65b9\u4e16\u7eaa\u57ce\u4e1c\u533a\u95e8\u5e02\u54c8\u54c8\u54c8\u54c8"
    }

编译器编译模板文件

为了提升解析效率和减少xml文件中的冗余数据,Tangram框架会将编写的xml布局文件编译为二进制文件。

实时预览工具

为了提升开发效率同样推出了实时预览工具

原生控件与虚拟控件

上面抛出个问题:可以看到控件的命名规则是以N和V开始,有什么区别呢?回复如下。
目前VirtualView提供的布局容器包含帧布局和线性布局,网格布局等,没有相对布局和约束布局的这些。因此当我们要实现一起布局效果的时候就需要嵌套很多次, 这样会影响渲染性能。基于以上问题VirtualView提出了原生控件与虚拟化控件,

原生控件:就是通过封装了系统原生 View 来实现的控件;(命名规则是以N开始)
虚拟化控件:使用 canvas 绘制创建的控件,它需要依托一个原生容器控件作为宿主容器,承重其最终的展示;(命名规则是以V开始)

它开创了一种虚拟化开发基础控件的技术,使用方只要按照指定协议实现一个基础控件的尺寸计算、绘制逻辑、布局逻辑,即能实现在宿主容器的 canvas 里实现直接绘制 UI 内容的,让最终渲染出来的视图结构呈现扁平化,提升组件渲染性能。同时为了解决虚拟化 View 带来的原生 View 的能力损失的问题,它支持加载和渲染原生基础控件,两者组合产生合力,既能最大限度发挥性能提升,又能满足特殊场景下的业务需求。

控件扩展

Tangram框架为我们内置了NText, VText, NImage, VImage等这些原生控件和虚拟控件。但是有些这些控件并不能满足我们所以的业务场景,如需要展示个性话进度条的View。这种情况如何处理呢,框架为我们提供了控件扩展的能力。
1.在编译工具配置文件配置映射关系 如 VIEW_ID_PicassoImage=1014
2. 在客户端实现并注册

    sViewManager.getViewFactory().registerBuilder(1014,new PicassoImage.Builder());

总结

Tangram通过提升布局灵活性和使用动态组件达到了较强了动态化能力。动态组件将我们xml布局文件的编写由native端移到server端,从而做到的界面动态化的能力。

参考

Tangram