在前面介绍了Tangram框架的历史由来和基本概念后,说明了Tangram解决了什么问题,可以用来做什么,核心是按照业务组件化粒度来实现动态流式页面。在此基础上本文着重分析iOS上Tangram框架如何使用json数据来动态生成流式页面。
Tangram如何用json描述页面
首先要通过json数据生成视图,我们得明白用怎么样的格式来描述一个页面。
无论是iOS或是Android UI是跟用户直接交互的重要部分,为了描述一个页面iOS和Android都有各自的一套解决方案和实现思路。平常native开发的更多的是一个2D的界面,为了描述这个界面,iOS和Android都抽象了一个View的概念,一个界面是由多个View组成的,View是页面的最小显示单位,而整个界面是从一个根View节点出发的,也就是一个页面就是一棵View组成的树。
最后这棵View树如何显示到屏幕上,这涉及到如何在平面坐标系上放置每个View,合成位图传到GPU,GPU上传到帧缓存,最后显示到屏幕上。
iOS上是View都有一个Frame,平面坐标系的x坐标、y坐标、宽和高,既每个View知道自己在父View的位置和宽高,而屏幕左上角为(0,0)坐标。这样最后通过计算可以知道每个View在屏幕的位置和大小,其中还有一个z坐标的概念,产生重叠知道哪个View在上,哪个在下。iOS上面是根据View的层级,默认从下往上的。随着iOS设备屏幕类型的增多,苹果也引入了AutoLayout,通过添加视图之间的关系约束,最后确定View的位置。
Android上面因为屏幕碎片化问题,使用的是layout+View的方式来布局,抽象出一个布局容器的类,通过布局容器类型,综合屏幕宽高、分辨率和View的约束最终确定每个View的位置。这样在不同屏幕上能有一致的显示效果。
Tangram要保证一套Json格式在多端的同一性,如果采用iOS的布局,Json会非常复杂,而且在Android上没办法适配,因此最后选择借鉴Android上的布局方案,使用布局+组件的形式来描述页面。
最后页面描述如下图:
最后页面由布局和组件组成的树形结构组成,组件其实就是一个业务组成的View,通过type映射成native的业务视图。
其中组件又由三部分组成,样式、业务数据和交互,布局也有样式。首先根据样式,参照Anroid抽象出style通用格式,包含margin、padding、width、height等,并支持扩展。Element的业务数据完全跟业务相关,由native和业务方约定,事件则抽离出来了EventBus。
Tangram参照Android的布局,使用Layout+Element+Event灵活一个页面,其中Layout、Element和Event通过type和端上做一一映射。
{
"type": "container-threeColumn",
"id": "173",
"style": {
"margin": [
"20",
"30",
"20",
"30"
]
},
"items": [
{
"type": "TmallComponent2",
"imgUrl": "https://gw.alicdn.com/tps/TB1Nin9JFXXXXbXaXXXXXXXXXXX-224-224.png",
"title": "榜单"
},
{
"type": "TmallComponent2",
"imgUrl": "https://gw.alicdn.com/tps/TB1Nin9JFXXXXbXaXXXXXXXXXXX-224-224.png",
"title": "最新"
},
{
"type": "TmallComponent2",
"imgUrl": "https://gw.alicdn.com/tps/TB1Nin9JFXXXXbXaXXXXXXXXXXX-224-224.png",
"title": "歌手"
}
]
}
Tangram整体框架和各模块功能
明白Tangram的json格式规范后,接下来就是native如何解析数据和生成视图了,在此之前,我们应该先从整体上把握这个框架的结构。最好的方式是先从模块划分、数据处理时序图、架构类图上面分析,避免一开始就深入某一个细节。
框架目录如下:
- Core:TangramView视图,自定义的类似TableView的视图,最外层容器
- EventBus:事件处理模块
- Factory:布局工厂、数据模型工厂、组件工厂,通过注册机制来创建对应类型的布局、模型和组件
- Helper:数据解析管理器和生成管理器,用来管理工厂和解析
- Model:通用组件数据模型
- Protocols:面向抽象接口编程,定义了工厂需要遵循的接口,布局、组件、数据模型需要遵循的协议,全部使用接口来定义,非常灵活
解析生成框架类图:
其中TangramDefaultDataSourceHelper类用来封装TangramDefaultLayoutFactory、TangramDefaultItemModelFactory、TangramDefaultElementFactory三个工厂,提供数据解析成Layout、ItemModel、Element,而这四个类遵循设计模式的开闭原则,都是用注册的方式,方便外接扩展,但是不建议修改。
TangramLayoutParseHelper类是专门用来解析layout数据的,这个类没有使用注册的方式来解耦合,是因为不同的layout之前有很多相似的逻辑,而且layout数据格式比较统一。
TangramView类图:
Tangram如何解析生成Layout和Element
通过上面的类图和机构图,说明了Tangram解析和生成这块用到的类,其中定义了很多接口,面向接口编程,同时使用工厂设计模式对修改关闭对扩展开放。
数据处理流程图:
执行详细流程图:
- 将json数据转为iOS系统的Array和Dictionary,使用TangramDefaultDataSourceHelper对数据进行解析
- TangramDefaultDataSourceHelper中调用注册的TangramDefaultLayoutFactory根据不同的类型将数据解析成不同的layout对象,同时调用TangramLayoutParseHelper解析类进一步解析数据,并填充数据到layout对象上
- 解析完layout后,调用注册的Item工厂TangramDefaultItemModelFactory解析ItemModel数据,ItemModel是Element的一个暂存数据对象
- ItemModel是定义的一个通用组件类,里面包含基础的属性,例如margin、height、width等,同时提供两个map来存储额外的样式数据和业务数据,以此来支持扩展
- 在TangramView调用代理方法,通知要显示相应位置的组件时,再次使用TangramDefaultDataSourceHelper,调用里面注册的TangramDefaultElementFactory工厂,根据ItemModel生成相应的组件视图,并填充相应的数据,同时将扩展的属性通过KVC映射到相应的组件上。
通过上面的一整套流程和框架,最终将json数据转换成页面显示到屏幕上。