tangram
tangram集成指南
1.简介
Tangram是什么
Tangram不仅仅是一个Native(iOS & Android)的界面开发框架,而是我们从日常工作中沉淀出的一套界面解决方案,涵盖了Native SDK,GUI操作台,后端逻辑容器,组件库机制的一整套方案。
tangram组成
页面
|
- 布局1
| |
| - 组件11
| |
| - 组件12
| |
| - 组件13
|
- 布局2
| |
| - 组件21
| |
| - 组件22
|
- 布局3
| |
| - 组件31
| |
| - 组件32
|
- 组件4
...
|
|
|
- 布局n
|
- 组件n1
页面:
在Android中是用RecyclerView来承载.
布局:
{
"type": "container-oneColumn", ---> 描述布局类型
"style": { ---> 描述样式
...
},
"header": { ---> 描述header
},
"items": [ ---> 描述组件列表
...
],
"footer": { ---> 描述footer
}
}
组件:
{
"type": "demo", ---> 描述组件类型
"style": { ---> 描述组件样式
"margin": [
10,
10,
10,
10
],
"height": 100,
"width": 100
}
"imgUrl": "[URL]", ---> 业务数据
"title": "Sample"
}
Tangram解决了什么问题
面向业务、多端一致性和高性能。
局限性
Tangram的动态能力很弱,动态能力局限在组件层面,无法动态卡片.
2.gradle集成
compile 'com.alibaba.android:tangram:2.0.5'
compile ('com.alibaba.android:virtualview:1.0.5@aar') {
transitive = true
exclude group: 'com.android.support'
}
compile ('com.alibaba.android:vlayout:1.2.8@aar') {
transitive = true
exclude group: 'com.android.support'
}
compile ('com.alibaba.android:ultraviewpager:1.0.7.7@aar') {
transitive = true
exclude group: 'com.android.support'
}
3.tangtam使用
基本使用:
初始化 Tangram 环境
Tangrambuilder.init(context, new IInnerImageSetter() {
@Override
public <IMAGE extends ImageView> void doLoadImageUrl(@NonNull IMAGE view,
@Nullable String url) {
//假设你使用 picasso 加载图片
Picasso.with(context).load(url).into(view);
}
}, ImageView.class);
初始化 TangramBuilder
TangramBuilder.InnerBuilder builder = TangramBuilder.newInnerBuilder(TangramActivity.this);
注册自定义的卡片和组件
- 注册绑定组件类型和自定义
View
,比如builder.registerCell(1, TestView.class);
。意思是类型为1的组件渲染时会被绑定到TestView
的实例上,这种方式注册的组件使用通用的组件模型BaseCell
。 - 注册绑定组件类型、自定义 model、自定义
View
,比如builder.registerCell(1, TestCell.class, TestView.class);
。意思是类型为1的组件使用自定义的组件模型TestCell
,它应当继承于BaseCell
,在渲染时会被绑定到TestView
的实例上。 - 注册绑定组件类型、自定义model、自定义
ViewHolder
,比如builder.registerCell(1, TestCell.class, new ViewHolderCreator<>(R.layout.item_holder, TestViewHolder.class, TestView.class));
。意思是类型为1的组件使用自定义的组件模型TestCell
,它应当继承于BaseCell
,在渲染时以R.layout.item_holder
为布局创建类型为TestView
的 view,并绑定到类型为TestViewHolder
的 viewHolder 上,组件数据被绑定到定到TestView
的实例上。
生成TangramEngine
实例
TangramEngine engine = builder.build();
绑定业务 support 类到 engine
engine.register(SimpleClickSupport.class, new XXClickSupport());
engine.register(CardLoadSupport.class, new XXCardLoadSupport());
engine.register(ExposureSupport.class, new XXExposureSuport());
绑定 recyclerView
setcontentView(R.layout.main_activity);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.main_view);
...
engine.bindView(recyclerView);
监听 recyclerView 的滚动事件
recyclerView.addOnscrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//在 scroll 事件中触发 engine 的 onScroll,内部会触发需要异步加载的卡片去提前加载数据
engine.onScrolled();
}
});
加载数据并传递给 engine
String json = new String(getAssertsFile(this, "data.json"));
jsonarray data = null;
try {
data = new JSONArray(json);
engine.setData(data);
} catch (JSONException e) {
e.printstacktrace();
}
退出的时候销毁 engine
engine.destroy();
自定义组件:
-
组件开发模式一,避免了反射调用,性能上更优:
-
实现一个自定义View,比如
XXTangramView
; -
实现接口
ITangramViewLifeCycle
,包含三个方法:
public void cellInited(BaseCell cell)
,绑定数据前调用;public void postBindView(BaseCell cell)
,绑定数据时机;public void postUnBindView(BaseCell cell)
,滑出屏幕,解除绑定;
-
主要在上述
public void postBindView(BaseCell cell)
完成组件业务逻辑;
-
-
组件开发模式二,动态绑定数据:
-
实现一个自定义View,比如
XXTangramView
; -
必须添加三个方法,以
@CellRender
注解,功能同模式一,只是被反射调用:
public void cellInited(BaseCell cell)
;public void postBindView(BaseCell cell)
;public void postUnBindView(BaseCell cell)
;
-
还可以为组件每个属性实现单独的设置方法,而不是在
postBindView
方法里一次性绑定数据,这些方法必须以@CellRender
注解,框架会在public void postBindView(BaseCell cell)
调用之前调用这些数据绑定方法;
-
4.VirtualView在Tangram中的使用
注册 VirtualView 版本的 Tangram 组件,只需要提供组件类型名称即可,
Tangram.Builder builder = Tangram.newBuilder(activity);
builder.registerVirtualView("tmallcomponent1");
builder.registerVirtualView("tmallcomponent2");
在 TangramEngine 构建出来之后加载模板数据,
tangramEngine.setVirtualViewTemplate(TMALLCOMPONENT1.BIN);
tangramEngine.setVirtualViewTemplate(TMALLCOMPONENT2.BIN);
...
还可以使用
tangramEngine.registerVirtualViewTemplate("tmallcomponent1",TMALLCOMPONENT1.BIN)
如何编写一个自定义基础控件
说明一下每个步骤:
- 先编写 XML 文件,如图所示引用了一个 NText 控件;
- 在 Config 文件里配置 NText 的标签名及属性的映射关系;像这种内置控件都已经配置好了,如果是自定义属性和控件,才要操作自己添加配置;配置文件含义参考这篇文章:VirtualView 工具大更新啦。在这个示例中,NText 标签被编译工具编译成数字 7,属性名 id、text、textSize、textcolor 都被编译成一个 hashcode 索引,真正的字符串值会存储到字符串资源区;属性值 title 也是被编译成一个 hashcode 索引,真正的字符串值会存储到字符串资源区;属性值 12 被直接编译成数字 12; 属性值 #333333 被编译成颜色值 -13421773;
- 编译工具根据 XML 文件和 Config 文件编译出一份二进制文件,交给客户端使用;
- 客户端初始化框架的时候会根据 id 注册控件,在这个示例中 7 代表了 NativeText 类控件,它就用来实例化 XML 里的 NText 标签;
- 最后将 XML 里 NText 下的属性传给 NativeText 实例进一步用于渲染;
创建控件实例的过程
以创建一个 PicassoImage 为例(虽然内置了 VImage 和 NImage 两个控件,但在实际业务场景中,还是使用一个自定义的图片控件比较合适,这样可以更好利用起结合图片库的内存管理、性能优化等 feature)。
目标
- 实现一个原生 Image 控件,使用 Picasso 加载图片
- 支持绑定 url 属性用来加载网络图片
- 支持绑定 degree 属性用来旋转图片
1. 定义标签名及其 id,属性名及类型
在编译工具里配置文件里定义:
VIEW_ID_PicassoImage=1014
,其中PicassoImage
就是 XML 里的标签名,id 值为 1014,这个是自定义的,建议从 1001开始,前 1000 保留给系统使用;degree=Float
,表示属性名是 degree ,属性值按 Float 类型编译解析;url=String
,表示属性名是 url,属性值按 String 类型编译,不过未在配置文件里声明的属性都是按 String 类型编译的,所以可以省略;
2. 定义控件的载体 View
取名 PicassoImageView
,继承 ImageView
,实现 IView
接口,因为 demo 比较简单,除此之外不做其他逻辑,主要实现 IView
的接口调用对应的系统 measure、layout 方法,因为这些方法是不能在外部调用的,只能通过 IView
的接口封装一下暴露出去。
事件处理
事件处理就涉及业务逻辑了,需要外部注册处理器。也是通过 EventManager
来注册,一种类型的事件注册一个处理器就可以了,如果注册了多个,那么在事件触发的时候,会回调每一个处理器。
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;
}
});
在处理函数里,可以获取到的资源有:
- 触发事件的组件 model:
data.mVB
- 组件绑定的原始 JSON 数据:
(jsonobject)data.mVB.getViewcache().getComponentData();
如果消化了事件,就返回 true
,否则返回 false
。
针对不同的控件,点击处理要做不同的逻辑,一般可以用以下方式来分发处理不同的点击事件:
String action = data.mVB.getAction()
获取所点击的控件的 action 字段,它是在 XML 目标里描述的,可以是一个常量值,也可从绑定的数据到数据。建议 actio 只是一个动作描述协议,比如跳转是一个 URL 格式的地址,其他的可以是自定义的协议;然后针对不同的协议地址,注册不同的处理模块,在自定义的 IEventProcessor
里分发处理。
5.virtual_tools的使用指南
下载源码之后,可执行工具存放在目录 TemplateWorkSpace 里,包含以下几个文件/目录(或运行后产生):
文件 | 作用 |
---|---|
config.properties | 配置组件 ID、xml 属性对应的 value 类型 |
templatelist.properties | 编译的模板文件列表 |
build | 二进制文件的输出目录 |
template | xml 的存放路径 |
compiler.jar | java 代码编译后 jar 文件,执行 xml 的编译逻辑 |
buildTemplate.sh | 编译执行文件 |
如何运行
- 打开命令行 执行
sh buildTemplate.sh
配置 config.properties
-
VIEW_ID_XXXX
- 配置 xml 节点 id
- 如配置
VIEW_ID_FrameLayout=1
,则 xml 节点中的<FrameLayout>
在编译后会用数值1代替 - 节点配置以 VIEW_ID_ 开头 - 自定义控件 id 从 1000 开始分配,前面 1000 保留给系统使用
-
property=ValueType
-
配置属性值的类型,配置对所有模板生效,不支持在 1.xml 和 2.xml 中对相同的属性用不同的 ValueType 解析
-
目前已经支持
-
常规类型:
String
(默认,不需要配置)、Float
、Color
、Expr
、Number
、Int
、Bool
-
特殊类型
Flag
、Type
、Align
、LayoutWidthHeight
、TextStyle
、DataMode
、Visibility
-
枚举类型
Enum<name:value,……>
- 枚举说明:
- 如配置
flexDirection=Enum<row:0,row-reverse:1,column:2,column-reverse:3>
- 在解析属性是配置
row
直接转化成int:0
,row-reverse
转成int:1
- 如配置
- 枚举说明:
-
-
-
DEFAULT_PROPERTY_XXXX
- 为了兼容就模板的编译,写的强制在二进制中写入一些属性类型定义,可以忽略
配置 templatelist.properties
-
格式
xmlFileName=outFileName,Version[,platform]
xml 文件模板编写
- 和以前的方式一样,不需要额外写 Java 代码,只需要对新增的属性在config.properties 中配置 ValueType
构建产物
- out目录:XML 模板编译成二进制数据的文件,其他内容都是以此为基础生成,上传到 cdn,通过模板管理后台下发的也是这里的文件;
- java目录:XML 模板编译成二进制数据之后的 Java 字节数组形式,可以直接拷贝到 Android 开发工程里使用,作为打底数据;
- sign目录:out 格式文件的 md5 码,供模板管理平台下发模板给客户端校验使用;
- txt目录:XML 模板编译成二进制数据之后的十六进制字符串形式,转换成二进制数据就是 java 目录下的字节数组;
接口模式
除了直接使用命令行执行工具,还可以基于此搭建完整成熟的模板工具,它可以是个客户端,也可以是个后端服务,或者是个插件,所以需要提供接口模式供宿主程序调用。
//初始化构建对象
ViewCompilerApi viewCompiler = new ViewCompilerApi();
//设置配置文件加载器,需要实现一个自己的 ConfigLoader,这里的 localConfigLoader 是示例
viewCompiler.setConfigLoader(new LocalConfigLoader());
//读取模板数据
fileinputstream fis = new FileInputStream(rootDir);
//调用接口,传入必备参数,参数二是模板名称类型,参数三是模板版本号,此时不区分平台,如果要区分平台,使用方单独编译即可
byte[] result = viewCompiler.compile(fis, "icon", 13);
6.通过一些思路解决开发中遇到的问题
通过自定义原子组件解决本地icon问题
一些复杂组件,使用原生书写完毕后,内置在APP中
相关阅读
Tangram 2.0 VirtualView Demo 配置
天猫开源了一个动态UI的方案,包含https://github.com/alibaba/VirtualView-iOShttps://github.com/alibaba/tangram-ios简单来个De