JavaScript开发人员社区热切欢迎Famo.us开源UI渲染框架于2014年Spring公开发布。 Famo.us承诺消除一些阻碍JavaScript和Web技术主导移动开发领域的最后瓶颈:缓慢的UI和糟糕的用户体验(UX)。
Famo.us以移动设备上的硬件图形处理单元(GPU)为目标,以实现尽可能最高的渲染帧速率,并且它添加了完善的物理引擎来实现令人满意的UX。 在为移动应用程序创建UI时,与Objective-C,Swift或Java™开发人员相比,JavaScript开发人员不再处于劣势。
本文介绍Famo.us的基本概念并探讨其设计。 然后,它动手处理了几个工作示例,包括一个典型的移动应用程序UI,您可以将其用作使用Famo.us开发的应用程序模板。 (请参阅下载以获取完整的示例代码。)
通过快速显示具有更改元素的连续页面(框架)来创建动画。 帧速率是每秒显示的帧数。 由于人类视觉的潜伏期,高帧频会产生运动的视觉错觉(电影背后的原理相同)。 为了在网页上创建动画,每帧都会修改元素的样式属性(位置,颜色和不透明度)。 这些属性的更新速度最终决定了UI的最大帧速率。 对于与Web应用程序的交互,每秒60帧(fps)被认为是平滑,类似于本机应用程序的UX的最佳速率。 当无法始终达到60 fps时,会出现不良的UX效果,例如颠簸和掉线(统称为Jank)。
Famo.us的核心是一个跨浏览器的高性能UI布局和优化库,具有自己的动画和物理引擎-用JavaScript编写。 Famo.us经过优化,可以在最短的时间内完成每帧的工作。 (最近的Famo.us基准测试表明,Famo.us在处理典型动画时每16.7 ms的帧可以花费少至1到2 ms,否则就没有性能开销。)然后,可以以最佳帧渲染目标UI。速率-通常至少为60 fps。 Famo.us项目致力于在所有后续版本中维持或改善此fps性能。
在操作上,Famo.us用其自己的高性能替代产品替换了典型的以DOM为中心的布局操作和2D或3D动画。 图1说明了Famo.us的内部工作原理。 浏览器的requestAnimationFrame()
(rAF)回调函数针对每一帧调用Famo.us引擎(单例对象)。 每秒六十次对应于每帧60 fps或1 / 60s(16.7 ms)。 每个回调在Famo.us中被称为引擎刻度 。
Famo.us API向开发人员展示了自己的一组高级可组合对象,例如表面 , 视图和小部件 。 您的Famo.us代码创建要渲染的场景图(在Famo.us中当前称为渲染树 ),连接事件处理,并指导或安排动画。
Famo.us场景图中的每个节点都是一个渲染节点 。 场景图被处理为渲染规范,并建立规范中间表示,Famo.us渲染组件在内部使用该中间表示来使目标的更新更加有效。
渲染组件以支持的帧速率(当前为60 fps)评估场景图,并将所需的更新输出到浏览器的DOM,Canvas元素或WebGL。 (Famo.us的beta实现仅针对浏览器的DOM。)Famo.us旨在在同一屏幕上输出到其任何受支持的目标,甚至同时(支持多模式操作 )。
在Famo.us,您撰写和动画renderables。 您使用的最低级别的通用可渲染对象是 Famo.us不会干预您获取此 “使用Famo.us进行编程时,您可以提高性能和渲染灵活性,以换取直接对页面DOM进行即时模式操作。 ” Famo.us的此体系结构类似于WebGL 3D渲染JavaScript库,包括Three.js和SceneJS。 了解异同可以帮助您快速掌握Famo.us: 看看实际的Famo.us应用程序可以帮助您锚定概念。 图2中的示例是Famo.us入门工具包中包含的默认应用程序,并且默认情况下也是由 在main.js中,单独的 在清单1中, 上下文 (与DOM节点相关联的微型DOM管理器)管理一个场景图,该场景图由节点内的所有DOM表示。 通常,您只有一个上下文实例(除非您正在从事特殊项目,例如多个透视图或平视显示器)。 修改器是Famo.us场景图中的渲染节点,它们修改位于其下方的渲染节点的某些属性(通常将转换应用于)。 您可以将多个修改器链接在一起,在这种情况下,转换矩阵会组合在一起,并且场景图的叶子始终是可渲染的。 在此示例中, 在图3中 ,九个点排列在3x3网格中。 [0.0]位于左上方,[1,1]位于右下方。 [0.5,0.5]是中心点。 其余点遵循此约定,例如,右上角[1,0]和左下角[0,1]。 此代码完成了图4中所示的简单场景图。 现在,Famo.us引擎评估内存中的场景图,并在rAF的驱动下有效地更新每帧的DOM,每秒大约更新60次。 每次, 总结一下: 为了进一步说明默认示例,下一个示例旋转了10个徽标实例,以10x10正方形的形式布置,在x轴和y轴之间交替旋转。 图5显示了最终的应用程序。 图6显示了此示例必须构造的场景图。 您可以看到此版本如何扩展前面的示例: 如清单2所示,用于创建修饰符并将其添加到每个徽标的上下文的代码与第一个示例类似。 它包含对每个帧进行动画处理和更新的计算工作。 这个应用程式有两个独立的转换功能,分别是 为了在x轴和y轴旋转之间交替,通过以下方式交替更改 与第一个示例一样,您在内存中设置了场景图,Famo.us引擎负责处理它并以rAF速率更新DOM。 在创建UI时,通常使用持续时间有限的动画。 一个示例是用户在到达滚动列表末尾时观察到的“反弹”。 另一个是从背面翻转一张扑克牌以露出其面Kong。 Famo.us通过 运行该应用程序时,您会在页面中间的Famo.us滚动视图中看到显示的developerWorks文章列表。 此列表在前10秒钟以恒定的速度绕y轴旋转。 然后,它猛烈地弹回并在接下来的10秒钟内反弹。 在进行这种持续时间有限的动画时,您可以连续滚动列表(如果使用的是桌面浏览器,请使用鼠标滚轮)。 图7显示了运行中的应用程序。 诸如文章滚动列表之类的视图是预制的更高级别的Famo.us组件(在本例中为 在清单3中 ,创建了一个名为 诸如 清单4显示了编程补间过渡的代码。 清单4中的代码首先将 在清单4中 ,第一个动画过渡持续10秒,滚动列表绕y轴以线性速度旋转。 当第一个补间完成时,将触发回调,第二个补间将使用 不必显式注册 您指定的渲染透视图(以像素为单位)与从查看者的“相机”到渲染场景的距离相关。 使用 到目前为止,这些示例都像3D渲染库一样操作Famo.us,但2D曲面除外-纯对象动画。 下一个示例确认这种构图和动画样式可以转换为移动UI的构造。 图8显示了常见的移动应用程序布局。 导航栏位于顶部,并且根据UI的状态激活“后退”和“更多”按钮(图8中未显示)。 底部是一个选项卡栏,该选项卡栏由一组切换按钮(可以使用CSS进行样式设置)组成,这些切换按钮用于选择在内容区域中显示的项目。 内容区域位于中间,大小可根据设备大小灵活调整。 通常,该应用包含用户可以进一步浏览的可滚动项目列表。 在这个示例应用程序中,您可以在developerWorks文章列表和开源电影列表之间进行选择。 当用户选择其中一项时,内容区域将更改以显示所选项目。 该项目可能仅在内容区域内打开(即,页眉和页脚仍可见)或占据整个屏幕(遮盖页眉和页脚)。 在您的移动浏览器中尝试该应用: 该应用程序启动时,将显示文章列表,如图9所示。 如果触摸选项卡栏中的“ 视频”按钮,则会显示开源电影列表,如图10所示。 如果您触摸列表中的视频之一,它将在内容区域中加载并播放,如图11所示。 在图11中,请注意,导航栏现在显示一个后退按钮。 如果您触摸该按钮,则会再次显示视频列表。 再次触摸文章以重新显示文章列表。 现在触摸文章名称之一。 该应用程序将加载并显示所选文章,如图12所示。 结合使用Famo.us视图和小部件,可以轻松创建移动应用程序UI。 可以将表面(通常是可渲染对象)和视图组成小部件。 视图可以在托管可渲染对象之间包含复杂的编排和交互逻辑。 使用Famo.us中的事件支持,视图可以接收,处理和发出事件。 小部件本身就是渲染节点,可以作为上下文场景图的叶子添加。 Famo.us附带了一系列现成的视图和小部件: 示例移动用户界面使用三个小部件: 使用可用的视图和小部件,移动UI成为场景图,如图13所示。 尽管上下文仍然位于树的根部,但树的修饰符和叶子不再容易辨认。 每个组成的Famo.us视图都封装了组件的管理详细信息,从而提供了预期的用户交互和行为-消除了对它们进行编码的需要。 要创建移动用户界面,您需要对场景图进行编码; 然后Famo.us引擎对其进行处理并以rAF速率更新DOM: 请注意突出显示的 现在指定了内存中的场景图,并且所有必需的事件处理程序都已连接好,以供Famo.us引擎处理。 检查在此示例中创建的Famo.us场景图(请参见图13 )。 您可以轻松地对其进行修改以选择和显示其他信息,只需更改数据源和修改样式即可。 这样的修改甚至可以被参数化和自动化。 本质上,您可以为“浏览列表并选择显示项目”移动应用程序的通用类创建UI应用程序模板。 随着时间的推移,可以构建此类应用程序模板的全面集合,以涵盖各种可能的应用程序区域。 创建本机代码移动应用程序很困难。 您不仅需要攀登陡峭的学习曲线,不仅需要多种移动操作系统(以及版本差异),而且还需要在每种平台上攀登不同的编程语言和数百种系统API。 添加专有或定制的工具带,再加上各种构建和部署管道和市场,您最终将获得大量必须跟上和支持的快速发展的技术。 即使您为应用程序准备了现成的样板代码,要在整个移动平台上使其适应新问题,也可能需要数周或数月的编码和调试。 同时,尽管有跨平台的承诺,但用于移动应用程序开发的Web技术仍远远未能交付本机代码UX(直到现在)。 Famo.us框架结合了浏览器优化方面的最新突破以及3D渲染库中的成熟概念,从而为移动Web应用程序提供了高性能,易于使用,高度自动化的UI创建平台。 现在,JavaScript开发人员可以轻松创建可提供与本机代码实现相媲美的用户体验的移动应用程序。 作者要感谢Famo.us的Andrew De Andrade和Larry Robinson在审阅本文时所提供的帮助。 还有珍妮·费尔德坎普(Jeanne Feldkamp)和史蒂夫·纽科姆(Steve Newcomb)的时间和采访。 翻译自: https://www.ibm.com/developerworks/web/library/wa-famous/index.htmlSurface
。 浏览器的DOM中显示的Surface
是Surface
,则可以看到
Surface
是VideoSurface
是 。
ImageSurface
是 。
InputSurface
是 。
CanvasSurface
是 。
Surface
类具有一个content
字段。 在此字段中,您可以添加要在Surface
上呈现HTML(在基础content
方式或位置,该content
是呈现为HTML的字符串。 该字符串是任何模板,数据源或数据绑定技术的自然集成点。 此外,由HTML在呈现的Surface
上形成的mini-DOM可以进行操作-除任何布局,包含或动画工作外,都应通过Famo.us完成。
与3D渲染库的比较
Scene
组件,可用于通过JSON构建复杂的场景图。 您可以通过渲染节点上的ID属性对其进行修改。 标记来控制布局。 CSS仅用于影响元素样式,不影响布局。 (HTML仍然很重要,因为当以DOM为目标时,所有可视元素都是HTML元素。)
使用Famo.us
generator-famous
的generator-famous
软件包generator-famous
(请参见运行Famo.us的三种方法 )。 该应用程序将绕着y轴平移Famo.us徽标的呈现形式。 图2.
generator-famous
生成generator-famous
生成的默认应用程序 ImageSurface
由清单1中所示的代码创建。 清单1.创建
ImageSurface
(提供给DOM )
var logo = new ImageSurface({
size: [200, 200],
content: '/content/images/famous_logo.png',
classes: ['backfaceVisibility']
});
content
选项对应于基础标记的
src
属性。 classes
选项将CSS类添加到HTML元素。 app.css中定义的backfaceVisibility
CSS类可确保用户可以看到徽标的backfaceVisibility
该类在app.css中定义为: .backfaceVisibility {
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
centerSpinModifier
包含一个origin
属性和一个transform
属性。 相对于所包含的父级(在本例中为Famo.us上下文)指定了origin
属性。 图3显示了指定Famo.us origin
的约定。 图3.设置
origin
属性的约定 centerSpinModifier
的transform
属性通过Transform.rotateY()
返回一个绕y轴旋转的函数: var initialTime = Date.now();
var centerSpinModifier = new Modifier({
origin: [0.5, 0.5],
transform : function() {
return Transform.rotateY(.002 * (Date.now() - initialTime));
}
});
mainContext.add(centerSpinModifier).add(logo);
图4.默认应用程序的场景图
centerSpinModifer
检查自initialTime
以来经过的时间,并围绕y轴递增旋转徽标。 您可以轻松地调整0.002常数以改变旋转速度。
logo
ImageSurface
。 Modifier
,该Modifier
是:
origin
= [0.5 0.5]) transform
Modifier
添加到场景图,然后在Modifier
正下方添加logo ImageSurface
。 扩展示例
图5.旋转了100个徽标实例的扩展应用
图6.扩展应用程序的场景图
清单2.旋转100个徽标的扩展代码示例
var mainContext = Engine.createContext();
var initialTime = Date.now();
function rotY() {
return Transform.rotateY(.002 * (Date.now() - initialTime));
}
function rotX() {
return Transform.rotateX(.002 * (Date.now() - initialTime));
}
for (var i=0; i< 10; i ++)
for (var j=0; j<10; j++) {
var image =
new ImageSurface({
size: [50, 50],
content: '/content/images/famous_logo.png'
});
var transMod =
new Modifier({
size: image.getSize.bind(image),
transform: Transform.translate(j * 50, i * 50, 0)
}
);
var rotMod =
new Modifier({
origin: [0.5, 0.5],
// xor
transform : (((i % 2) !== (j % 2)) ? rotY : rotX)
});
mainContext.add(transMod).add(rotMod).add(image);
rotY
绕y轴旋转和rotX
绕x轴旋转。 场景图的分支是在嵌套的i
- j
循环中创建的。 添加到每个分支的两个修饰符分别命名为transMod
(徽标图像到位的翻译)和rotMod
(徽标围绕其原点的旋转)。 rotMod
的transform
属性: transform : (((i % 2) !== (j % 2)) ? rotY : rotX)
动画的过渡和补间
Transitionable
类支持过渡,该类表示可以随时间进行过渡的属性。 下一个示例显示了两个补间过渡的用法。 图7.滚动文章列表绕补间过渡动画的y轴旋转
ScrollContainer
),可以将它们组合在一起以方便地创建UI。 下一个示例更详细地探讨了Famo.us的视图和小部件。 现在,足以了解滚动列表由Famo.us Surface
的序列集组成。 清单3显示了列表创建代码。 清单3.创建文章滚动列表
function createArticlesList() {
artListSVC = new ScrollContainer({
scrollview: {direction: Utility.Direction.Y}
});
var lines = [];
artListSVC.sequenceFrom(lines);
for (var i in articles) {
var surf = new Surface({
content: '
lines
的Famo.us Surface
数组。 创建的每个Surface
显示一篇developerWorks文章的名称。 创建一个名为artListSVC
的Famo.us ScrollContainer
,并使用其sequenceFrom()
方法配置带有lines
数组的滚动列表。 编程补间过渡
artListSVC
的视图也是可渲染的(使用可渲染的树叶管理其自己的内部场景图)。 可以通过一个或多个修饰符对视图进行转换,然后将其添加到上下文的场景图中,如前面的示例所示。 将artListSVC
添加到上下文的代码是: var sm = new StateModifier({align:[0.5, 0.5],
origin: [0.5, 0.5]});
mainContext.add(sm).add(artListSVC);
StateModifier
是一个随时间(内部,通过Transitionable
)维护状态的修改器。 使用补间过渡设置动画时,仅指定开始和结束状态(也称为关键帧 )。 补间过渡会插补中间状态值,并在每个刻度上将它们提供给渲染引擎。 您无需在自己的代码中计算或维护中间状态。 清单4.补间过渡动画
Transitionable.registerMethod('tween', TweenTransition);
sm.setTransform(Transform.rotateY(Math.PI), {method: 'tween',
curve:'linear', duration:10000},
function() {
sm.setTransform(Transform.rotateY(2 * Math.PI),
{method: 'tween', duration: 10000,
curve: 'spring'});
});
TweenTransition
注册为带有Transitionable
的tween
方法。 然后,使用StateModifier
的setTransform()
方法添加补间的rotateY
变换。 setTransform()
方法将转换作为第一个参数,将Transitionable
作为第二个参数,并将完成回调函数作为第三个参数。 spring
并在接下来的10秒钟弹跳的spring
曲线。 TweenTransition
,因为如果未为Transitionable
指定method
属性,则TweenTransition
默认使用TweenTransition
。 但是, 清单4展示了如何注册另一种转换方法,例如从Famo.us物理引擎转换。 (Famo.us物理引擎的覆盖范围不在本文的讨论范围之内。) 渲染角度
Context.setPerspective()
设置此值。 较小的值可使观看者在保持相同视场的同时更靠近渲染的对象,并且大致类似于相机上的广角镜。 通过改变视角,可以增强许多动画的外观。 在此示例中,将Perspective设置为500,以获得更显着的效果。 将Famo.us应用于典型的移动应用程序UI
图8.在Famo.us中组成移动应用程序UI
试用应用
图9. developerWorks文章的应用程序显示
图10.开源视频的应用程序显示
图11.播放电影的应用程序
图12.所选文章的应用程序显示
使用Famo.us视图和小部件
Scrollview
控制可渲染Scrollview
的顺序列表(在x或y方向上),并允许使用触摸或鼠标在列表中滚动(通常是在一系列表面上)。 HeaderFooterLayout
管理三个可渲染对象:指定大小的页眉和页脚,以及可变大小的内容区域。 该视图用于布置示例的移动UI。 EdgeSwapper
是一个容器,用于通过从父级边缘EdgeSwapper
滑动多个可渲染对象来管理它们的显示。 示例移动用户界面使用此视图显示两个可滚动列表。 ScrollContainer
是一个视图,其中包含一个Scrollview
和一个用于裁剪ScrollView
的显示内容的托管Surface
。 示例移动用户界面在HeaderFooterLayout
的内容区域中使用ScrollContainer
来显示文章或视频的列表。
NavigationBar
是一个微型应用程序视图,管理标题表面和两个可单击表面的显示,这两个表面分别表示导航条的“后退”和“更多”按钮。 窗口小部件会back
并产生more
事件。 TabBar
管理水平或垂直布局的小部件栏。 (默认为切换按钮。)选择了托管窗口小部件时,其相应的ID与select
事件一起发出。 ToggleButton
是一个打开或关闭的按钮,它显示两个托管曲面。 图13.移动应用程序UI的场景图
ScrollContainer
其中包含一个管理Surface
列表(列表中的单元格)的Scrollview
,每篇文章一个: function createArticlesList() {
artListSVC = new ScrollContainer({
scrollview: {direction: Utility.Direction.Y}
});
var lines = [];
artListSVC.sequenceFrom(lines);
for (var i in articles) {
var surf = new Surface({
content: '
content
属性,该属性设置为用于呈现列表中单元格HTML,以及相关CSS类。 itemType
和listIndex
是两个自定义属性,用于标识在click
事件处理程序中选择的实际数据项。 Surface
以显示选定的文章: function createWebSurface() {
wb = new Surface(
);
}
Surface
以显示选定的视频: function createVideoSurface() {
vs = new VideoSurface(
{
size: [undefined,undefined],
autoplay: true
}
);
}
NavigationBar
小部件并将其添加到标题中: function addHeader() {
nb = new NavigationBar({
size: [undefined, 75],
content: 'dW Famo.us',
moreContent: '',
backContent: '',
properties: {
lineHeight: '75px'
}
});
layout.header.add(nb);
eh.subscribe(nb);
eh.on('back', function() {
rc.setOptions({
inTransition: false,
outTransition: true
});
if (backTarget !== undefined)
rc.show(backTarget);
setNavbarBack(false, undefined);
});
}
EdgeSwapper
视图并将其添加到内容区域。 该控制器交换文章列表,视频列表,一篇文章的显示或一部视频的显示: function addContent() {
rc = new EdgeSwapper({
overlap: false,
outTransition: false,
size:[undefined, undefined]
});
layout.content.add(rc);
}
function addFooter() {
var tb = new TabBar({
});
layout.footer.add(tb);
tb.defineSection(0,{content: 'Articles', onClasses: ['tabbuton'], offClasses: ['tabbutoff']});
tb.defineSection(1,{content: 'Videos', onClasses: ['tabbuton'], offClasses:['tabbutoff']});
tb.select(0);
eh.subscribe(tb);
eh.on('select', function(but) {
rc.setOptions({
inTransition: false,
outTransition: false
});
switch (but.id) {
case 0:
rc.show(artListSVC);
break;
case 1:
rc.show(vidListSVC);
break;
}
setNavbarBack(false, undefined);
});
}
CSS的tabbuton
类样式按钮的状态,并tubbutoff
风格关闭状态。 如果触摸按钮0
,则select
事件的事件处理程序将显示文章列表;如果触摸按钮1
则事件显示将显示视频列表。 Scrollview
的选择发出的click
事件添加事件处理程序: function init() {
rc.show(artListSVC);
eh.on('click', function(obj) {
rc.setOptions(
{
inTransition: true,
outTransition: false
});
var surfaceProps = obj.origin.getProperties();
if (surfaceProps.itemType === 'article') {
wb.setContent('');
rc.show(wb);
setNavbarBack(true, artListSVC);
}
else
{ // video
vs.setContent(videos[surfaceProps.listIndex].url);
rc.show(vs);
setNavbarBack(true, vidListSVC);
}
});
}
结论
致谢
你可能感兴趣的:(java,python,javascript,webgl,html,ViewUI)