可 Web 编程的 NativeUI 设计与实现 张袁炜
zhangyuanwei@baidu.com 欢迎转岗简历请发
About Me @ 张袁炜 直达号 网址导航 百度 音乐 前端 Node.js Android Arduino RaspberryPI https://github.com/zhangyuanwei
Outline 一个 Hybrid App 的进化史 Native UI 实现原理 架构设计 UI 构建 布局系统 Web 样式 支持 事件机制 性能优化 前端框架设计
一个 App 的进化
一个 App 的进化 地理位置 分享 摄像头 支付
一个 App 的进化 地理位置 分享 体验 交互 动画 性能 摄像头 支付
一个 App 的进化
一个 App 的进化
一个 App 的进化 CSS3 硬件加速? 改 WebKit? 单 页 面应 用? 手势跟随?
一个 App 的进化 WebView Native WebView WebView
一个 App 的进化 background page WebView WebView WebView // 系统原 生事件, // 新 activity 创建的时候触发 webview_regist // activity 销毁的时候触发 webview_unregist // var _events = ['webview_register', var bridge = window.lc_bridge; var webviews = {}; var status = { ACTIVE: 1, PAUSED: 2, STOPPED: 3, KILLED: 0 }; // 监听 activity webview 创建事件 document.addeventlistener('webview_reg if (!(event.origin in webviews)) { webviews[event.origin] = { origin: event.origin, status: status.active, data: event.data }; } });
代码重构 内存泄露 多 页 面通讯
理想架构? 性能好 ( 媲美 Native) 定制性强 ( 媲美 Web) 学习成本低 ( 最好为零 )
页 面增强 底层为 WebView Native WebView 覆盖透明 Native 组件层 Native 组件替换 Web 组件
页 面增强
页 面增强 页 面加载 是否有 Native 提取数据 / 样式 创建 Native 组件 初始化组件交互 隐藏 Web 组件 结束
Blend UI 系统架构 App Title Tab Dialog Toast Widget Factory Zepto Browser Javascript API Javascript <-> Native bridge Native
Blend UI 系统架构 Title Tab Dialog Toast View Text TextInput Image AlphaAnimation Element Animation Queue Javascript <-> Native bridge View Text TextInput Image Native AlphaAnimation
UI 构建 提 示信息 提 示内容 Dialog 确定 取消
UI 构建 提 示信息 提 示内容 确定 取消
UI 构建 提 示信息 View 提 示内容 View View View Text Text View View Text Text 确定 取消
UI 构建 createview("tag":string, "type":string, config :object) 根据给定的 config 配置, 创建 一个类型为 type 的基础 GUI 组件, 并指定 tag addview("parenttag":string, "childtag":string, index :number) 添加 childtag 所指定的 View 到 parenttag 所指定 View 的 index 位置 Javascript <-> Native bridge removeview("parenttag":string, "index": number) 从 parenttag 所指定 View 删除 index 位置的 子 View updateview("tag":string, "type":string, config :object) 更新 tag 所指定的 View
Blend UI 系统架构 Title Tab Dialog Toast View Text TextInput Image AlphaAnimation Element Animation Queue Javascript <-> Native bridge View Text TextInput Image Native AlphaAnimation
Blend UI 系统架构 Javascript <-> Native bridge Tag Map View Tree CssNode Tree View Text TextInput Image AlphaAnimation Native CssNode BorderDrawable Android View System
CSS Layout CssNode public void addchildat(cssnode child, int i) public void removechildat(int i) public void setflexdirection(cssflexdirection direction) public void setjustifycontent(cssjustify justifycontent) public void setalignitems(cssalign alignitems) public void setalignself(cssalign alignself) public void setpositiontype(csspositiontype positiontype) public void setwrap(csswrap flexwrap) public void setflex(float flex) public void setmargin(int spacingtype, float margin) public void setpadding(int spacingtype, float padding) public void setborder(int spacingtype, float border) public void setpositiontop(float positiontop) public void setpositionbottom(float positionbottom) public void setpositionleft(float positionleft) public void setpositionright(float positionright) public void setstylewidth(float width) public void setstyleheight(float height)
CSS Layout CssNode public void calculatelayout() public boolean hasnewlayout() public void marklayoutseen() public float getlayoutx() public float getlayouty() public float getlayoutwidth() public float getlayoutheight()
CSS Layout CssNode View Node View View View Node Node Node Text Text View View Node Node Node Node Text Text Node Node
CSS Layout CssNode flex:1 border:1 flexdirection: column Node border:1 justifycontent: center Node Node Node border:1 justifycontent: space-between Node Node Node Node Node Node
CSS Layout CssNode calculatelayout x:0 y:0 width:400 height:300 Node x:1 y:1 width:398 height:40 Node Node Node x:1 y:260 width:398 height:42 Node Node Node Node Node Node https://github.com/zhangyuanwei/csslayout
Blend UI 系统架构 Javascript <-> Native bridge Tag Map View Tree CssNode Tree View Text TextInput Image AlphaAnimation Native CssNode BorderDrawable Android View System
Border Drawable
Border Drawable
Border Drawable BorderDrawable https://github.com/zhangyuanwei/borderdrawable
Blend UI 系统架构 Javascript <-> Native bridge Tag Map View Tree CssNode Tree View Text TextInput Image AlphaAnimation Native CssNode BorderDrawable Android View System
Blend UI 系统架构 Title Tab Dialog Toast View Text TextInput Image AlphaAnimation Element Animation Queue Javascript <-> Native bridge View Text TextInput Image Native AlphaAnimation
事件机制 Javascript <-> Native bridge webview.loadurl( javascript:xxxx ); (function(){ var event = document.createevent( Event"); // 事件固定名称为 "boost", 方便 Js 统 一监听 event.initevent("boost", false, false); // 事件数据 event.data = somedata; // 事件源的 Tag event.origin = origintag"; // 具体的事件类型 event.boosteventtype = "touchend"; document.dispatchevent(event); })();
事件机制 Element document.addeventlistener("boost", function (e) { var target = getelementbytag(e.origin); if (!target) { return; } assert(target instanceof Element, target); var event = { type: e.boosteventtype, target: target, data: e.data, }; target.dispatchevent(event); }, false);
Blend UI 系统架构 Title Tab Dialog Toast View Text TextInput Image AlphaAnimation Element Animation Queue Javascript <-> Native bridge View Text TextInput Image Native AlphaAnimation
性能优化 Queue var view = boost.createelement("view"); view.style.position = "absolute"; view.style.top = 100; view.style.left = 100; view.style.width = 200; view.style.height = 200; view.style.backgroundcolor = "#ff6600"; var text = boost.createelement("text"); text.style.color = "#000000"; text.style.fontsize = 20; text.value = "hello world"; view.appendchild(text); boost.rootelement.appendchild(view);
性能优化 Queue var view = boost.createelement("view"); // createview view.style.position = "absolute"; // updateview view.style.top = 100; // updateview view.style.left = 100; // updateview view.style.width = 200; // updateview view.style.height = 200; // updateview view.style.backgroundcolor = "#ff6600"; // updateview var text = boost.createelement("text"); // createview text.style.color = "#000000"; text.style.fontsize = 20; text.value = "hello world"; view.appendchild(text); boost.rootelement.appendchild(view); // updateview // updateview // updateview // addview // addview
性能优化 Queue updateview addview createview updateview updateview createview Timer callqueue
性能优化 Queue function queue(callback) { var list = []; var running = false; function flush() { running = false; callback(list); list = []; } } return function (cmd) { list.push(cmd); if (!running) { settimeout(flush, 0); running = true; } };
性能优化 Queue updateview addview createview updateview updateview createview Timer callqueue
性能优化 Queue updateview addview createview updateview createview Timer callqueue
性能优化 Queue window.lc_bridge.callqueue("commands": jsonstring); [ // 第 一个命令 { "tag": string, // 需要调 用函数的 目标 Tag "method": string, // 函数名 "args": [ // 参数列表 object, // 参数 1 object, // 参数 2... ] }, callqueue // 第 二个命令 {... }, ] //...
性能优化 Queue updateview addview createview updateview createview Timer callqueue
性能优化 addview createview updateview updateview createview Js 反射 addview createview updateview updateview createview Native
性能优化 addview createview updateview updateview createview 提取 switch (methodid) { case 80: addview(); break; case 81: createview(); break; case 82: updateview(); break; default: break; }
Blend UI 系统架构 Title Tab Dialog Toast View Text TextInput Image AlphaAnimation Element Animation Queue Javascript <-> Native bridge View Text TextInput Image Native AlphaAnimation
Dom API 模拟 var view = boost.createelement("view"); view.style.position = "absolute"; view.style.top = 100; view.style.left = 100; view.style.width = 200; view.style.height = 200; view.style.backgroundcolor = "#ff6600"; boost.rootelement.appendchild(view); var text = boost.createelement("text"); Dom API 模拟 Style 属性 text.style.color = "#000000"; text.style.fontsize = 20; text.value = "hello world"; view.appendchild(text);
事件模拟 view.addeventlistener("touchend", function (event) { text.value = "doun't touch me!"; view.style.top = Math.random() * 400; view.style.left = Math.random() * 400; }, false); Dom 事件
HTML & CSS 解析 类 HTML 支持 CSS 样式 支持
CSS 选择器实现 jquery/zepto 支持
前端框架 Title Tab Dialog Toast XmlParser StyleParser jquery/zepto Widget View Text TextInput Image AlphaAnimation NativeElement CustmerElement NativeObject Element StyleSheet Selector Native EventTarget
Thanks