Tangram + Virtualview Android 初体验

Tangram + Virtualview Android 初体验

Tangra

前言

Tangram:阿里开源的一套动态化构建 Native 页面的框架,相较于一些H5的动态实现,它拥有天生亲和系统交互的优势。

Virtualview:同样是阿里开源的一套组件动态化方案,可以通过自定义XML方式引用这些组件来搭建UI视图。

当Tangram遇上Virtualview后,我们就可以在不重新打包的情况下,很好的实现页面的动态修改,同时页面的交互也能拥有更好的原生体验。接下来我们通过一个简单的demo来了解下它们的使用。

Git

TangramDemo:https://gitee.com/zhengdd/TangramDemo

开发使用

一、Tangram项目创建

首先我们需要创建一个TangramDemo项目,然后在module的build中做如下引用,这些都是在tangram使用时需要的一些框架。


    compile 'com.alibaba.android:tangram:2.0.5@aar'

    compile 'io.reactivex.rxjava2:rxjava:2.1.12'

    compile 'io.reactivex.rxjava2:rxandroid:2.0.2'

    compile('com.alibaba.android:virtualview:1.3.8@aar') {

        transitive true

    }

    compile('com.alibaba.android:vlayout:1.2.18@aar') {

        changing = true

    }

    compile ('com.alibaba.android:ultraviewpager:1.0.7.7@aar') {

        transitive = true

    }

然后我们需要在Application的onCreate()方法中进行初始化,其中图片加载,可以根据使用的框架不同进行修改,我这边使用的是Glide。


        TangramBuilder.init(context, new IInnerImageSetter() {

            @Override

            public <IMAGE extends ImageView> void doLoadImageUrl(@NonNull IMAGE view, @Nullable String url) {

                Glide.with(getApplicationContext()).load(url).into(view);

            }

        }, ImageView.class);

二、Tangram在Activity中的使用

因为Tangram是通过RecyclerView进行动态化布局实现的,所以我们在创建activity页面布局时在需要动态化是实现的区域使用RecyclerView控件即可

然后我们需要在activity中初始化TangramBuilder并与RecyclerView想绑定。


    private RecyclerView mRecyContext;

    private TangramEngine engine;

    private TangramBuilder.InnerBuilder builder;



    builder = TangramBuilder.newInnerBuilder(context);

    engine = builder.build();

    //绑定view

    engine.bindView(mRecyContext);

    //关联滑动监听

    mRecyContext.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override

            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                super.onScrolled(recyclerView, dx, dy);

                engine.onScrolled();

            }

        });

同时我们可以通过注册一些辅助业务到engine中帮助我们的进行一些逻辑处理,如点击事件,数据加载等一些处理逻辑。


    engine.register(SimpleClickSupport.class, new SimpleClickSupport() {

            @Override

            public void setOptimizedMode(boolean optimizedMode) {

                super.setOptimizedMode(optimizedMode);

            }

            @Override

            public void onClick(View targetView, BaseCell cell, int eventType) {

                super.onClick(targetView, cell, eventType);

            }

            @Override

            public void onClick(View targetView, Cell cell, int eventType) {

                super.onClick(targetView, cell, eventType);

            }

            @Override

            public void onClick(View targetView, BaseCell cell, int eventType, Map<String, Object> params) {

                super.onClick(targetView, cell, eventType, params);

            }

            @Override

            public void defaultClick(View targetView, BaseCell cell, int eventType) {

                super.defaultClick(targetView, cell, eventType);

            }

        });

        engine.register(CardLoadSupport.class, new CardLoadSupport());

        engine.register(ExposureSupport.class, new ExposureSupport() {

            @Override

            public void onExposure(@NonNull Card card, int offset, int position) {

            }

        });

当然,因为我们结合Virtualview使用,也需要注册一些Virtualview相关的一些逻辑服务。


private void initVirtual() {

        VafContext vafContext = engine.getService(VafContext.class);

        //图片加载我们可以更加框架自定义Target实现

        vafContext.setImageLoaderAdapter(new IImageLoaderAdapter() {

            @Override

            public void bindImage(String uri, final ImageBase imageBase, int reqWidth, int reqHeight) {

                GlideVVSimpleTarget target = new GlideVVSimpleTarget(imageBase);

                target.setSize(reqWidth, reqHeight);

                BitmapTypeRequest bitmapTypeRequest = Glide.with(getApplicationContext())

                        .load(uri).asBitmap();

                if (imageBase.getTag() != null) {

                    bitmapTypeRequest.transform(new CircleTransform(context)).into(target);

                } else {

                    bitmapTypeRequest.into(target);

                }

            }

            @Override

            public void getBitmap(String uri, int reqWidth, int reqHeight, final Listener lis) {

                GlideVVSimpleTarget target = new GlideVVSimpleTarget(lis);

                target.setSize(reqWidth, reqHeight);

                Glide.with(getApplicationContext())

                        .load(uri).asBitmap().into(target);

            }

        });

//注册单击事件的逻辑实现

        vafContext.getEventManager().register(EventManager.TYPE_Click, new IEventProcessor() {

            @Override

            public boolean process(EventData data) {

            //我们可以通过定义数据设置的值不同做不同处理

                String action = data.mVB.getAction();

                return true;

            }

        });

        vafContext.getEventManager().register(EventManager.TYPE_Exposure, new IEventProcessor() {

            @Override

            public boolean process(EventData data) {

                //handle here

                return true;

            }

        });

        vafContext.getEventManager().register(EventManager.TYPE_LongCLick, new IEventProcessor() {

            @Override

            public boolean process(EventData data) {

                return true;

            }

        });

    }

三、数据加载绑定

最后我们就可以通过网络请求获取data.json数据后进行注册virtualview和绑定数据动态展现页面了。其中数据可以通过virtualview_tools进行编译生成,这个在后面会讲,生成后的数据格式为json格式,主要包含templates和data两个字段的数据。

其中templates为Virtualview自定义xml通过编译后获取的字符串,为数组类型,创建了几个xml则templates数据个数就为几个。

data则为展示数据的结构与内容。

结构如下:


{

    "templates": [],

    "data": {

        "jsondata": [

            {

                "items": [

                ],

                "style": { 

                },

                "type": "container-oneColumn"

            }

        ]

    }

}

activity中数据绑定如下:


        PreviewData data = (PreviewData) msg.getData().get("data");

                        for (int i = 0; i < data.templates.size(); i++) {

                            String vvname = name + i;

                            //注册布局名称,与xml文件名相同

                            builder.registerVirtualView(vvname);

                            //设置ui布局数据

                            engine.setVirtualViewTemplate(JSONutils.getBase64(data.templates.get(i)));

                        }

                        com.google.gson.JsonArray jsonArray = data.data.getAsJsonArray("jsondata");

                        String json = jsonArray.toString();

                        JSONArray jsdata = null;

                        try {

                            jsdata = new JSONArray(json);

                            //绑定动态页面结构数据并显示

                            engine.setData(jsdata);

                            engine.refresh();

                        } catch (JSONException e) {

                            e.printStackTrace();

                        }

动态编辑

一、VirtualView工具使用

在demo中,我们实现类似如下结构的一个布局页面。

-w518

首先我们在⁨ virtualview_tools⁩ ▸ ⁨compiler-tools⁩ ▸ ⁨RealtimePreview⁩ ▸ templates目录下创建一个KouBeiHome目录,文件结构如下图

-w580

其中.xml文件是我们根据页面编写的ui,KouBeiHome.json则是Tangram的数据结构。

然后我们通过控制台运行sh run.sh ,成功编译后会生成data.json文件。然后可以由上文中Tangram动态获取绑定实现动态页面。

二、UI实现

关于一些VirtualView组件及属性的了解,可以看这里

在编写ui页面时候,我们需要先吧一些基础元素抽取出来。

比如
-w91

结构会被重复使用,便需要抽取出来构建ui,成KouBeiHome0.xml.内容格式如下


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

<VHLayout

orientation="V"

layoutWidth="wrap_content"

layoutHeight = 'wrap_content'

flag = "flag_clickable"

action = "${action_mune}">

<NImage

tag = "Circle"

layoutWidth= '50'

layoutHeight='50'

src = "${mune_icon_url}"

layoutGravity='h_center'/>

<NText

layoutWidth= 'wrap_content'

layoutHeight='wrap_content'

text = '${mune_item_text}'

textSize = "15"

layoutGravity='h_center'/>

</VHLayout>

同样其他一些重复结构也被抽取实现,如

-w518
-w164

通过KouBeiHome3和KouBeiHome2实现。

最后把整体布局通过KouBeiHome4实现,具体如下


<VHLayout

orientation="V"

layoutWidth="match_parent"

layoutHeight="match_parent"

background="#ff7746">

<Grid

layoutMargin = "10"

layoutWidth="match_parent"

layoutHeight="wrap_content"

colCount = "5"

itemVerticalMargin = "5"

dataTag ="${mune_list}"/>

<NImage

flag = "flag_clickable"

layoutWidth="match_parent"

layoutHeight="140"

src = "${banner_url}"/>

<Grid

layoutWidth = "match_parent"

layoutHeight = "wrap_content"

dataTag = "${title_01}"

colCount = "1"

itemHorizontalMargin = "1"/>

<Grid

layoutHeight = "80"

layoutWidth = "match_parent"

layoutMargin = "10"

itemHorizontalMargin = "5"

colCount = "3"

dataTag = "${fuli_list}"/>

<Grid

layoutWidth = "match_parent"

layoutHeight = "wrap_content"

dataTag = "${title_02}"

colCount = "1"

itemHorizontalMargin = "1"/>

<Grid

layoutHeight = "wrap_content"

layoutWidth = "match_parent"

layoutMargin = "10"

itemHorizontalMargin = "5"

colCount = "3"

dataTag = "${miaosha_list}"/

</VHLayout>

三、数据编辑

根据Tangram组件规则与上述ui设置的字段名进行数据设置。


"items": [

                {

            "type": "KouBeiHome4",

            "mune_list": [······],

            "banner_url": "https://img.alicdn.com/tfs/TB12eXNsVzqK1RjSZSgXXcpAVXa-750-291.jpg_Q90.jpg",

            "title_01": [

                {

                    "type": "KouBeiHome3",

                    "item_title": "1212福利社",

                    "item_title_more": "更多",

                    "enum_visibility":"gone"

                }

            ],

            ······

                }

        ]

总结

以上就是通过Tangram 和 Virtualview 结合实现动态页面的最基础的一些使用了。

总的来说,通过VirtualView,我们实现每一个xml文件都相当于一个组件,然后我们吧这些组件动态注册到Tangram中去,这样我们就能使用这些组件构建动态构建页面了。

然后Tangram通过动态加载数据,组合这些组件并设置数据,就实现了动态加载页面。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容