就企业级开发而言,Adobe® Flex SDK 经历了如此巨大的变化,以致很难相信它还是原来那个产品。本文介绍如何使用开源 Flex 4 beta SDK 探索创建 SaaS(Software as a Service,软件即服务)RIA(Rich Internet Application)的新特性和新功能。
近年来,RIA 开发和 SaaS 的工具箱和框架的数量一直在增加。2004 年并购 Macromedia 之后,Adobe Systems 继承了 Flex —— 一个我们现在称为 RIA 的构建框架。Adobe 决定将 Flex SDK 作为一个开源框架,但是,用于构建 Flex 应用程序的基于 Eclipse 的工具仍旧是需要许可的软件产品,这个工具的品牌名称最近由 Adobe Flex Builder 变更为 Adobe Flash Builder。
随着基于云的 SaaS 的快速增长,不难发现 Flex 框架是 RIA 开发使用得最为广泛的工具。Flex 之所以与其他应用程序不同,是因为运行它的引擎 — Flash Virtual Machine — 最初是为富图形编写的。富图形可以用于最大化所谓的用户体验设计,这使得 Flex 成为创建高级 UI 的一个好工具。作为 Flash 平台的一部分,Flex 对于生成平滑数据驱动的图形和高级过渡特别有用。有一点不可否认,Flex 的流行很大程度上源于它创建更好的用户体验的能力。
本文将详细介绍 Flex 4 SDK 的组件,这些组件能够进一步提高您创建高级 RIA UI 的能力。
皮肤和主题
Flex 4 SDK 团队的三个主要目标之首就是 “Design in Mind”。Flex SDK 产品经理 Matthew Chotin 解释说:“Design in Mind 主题的最显著特征就是我们的新的皮肤和组件架构,即 Spark。Spark 构建于现有的 Halo 架构之上,为开发人员和设计人员提供了一种更具表达能力的机制,使他们能够相互协作,共同创建他们的 Flex 应用程序的外观。”
由于这个目标,设计 RIA 比以前任何时候更加容易,Adobe 对于创建一个更统一的产品生命周期的关注意味着,用户体验能够在产品开发生命周期中不断改善。简而言之,即使用户体验设计预算费用呈线性增长,而 SaaS 的成功几率将呈指数级增长(如下图所示)。
图 1. 用户体验设计和 ROI 之间的关系
Spark 和 SaaS
Spark 库是 Design in Mind 创新的主要支柱之一,它包含在组件内部管理其状态的组件。您可以通过扩展 SkinnableComponent(如 清单 1 所示)而不是 UIComponent(这在使用 Halo 库时使用)来进行控制,从而利用这个功能。另外,您可以使用 MXMLComponent 对象扩展 MXML 组件,使用 Group 对象扩展用于封装一个组件数组的多个组件,以及使用 SkinnableContainer 对象(如您所料)扩展容器组件。
清单 1. 用 MXML 声明的 SkinnableContainer 组件
<?xml version="1.0" encoding="utf-8"?><s:SkinnableContainer skinClass="mySkin"> <s:layout> <s:VerticalLayout horizontalAlign="center"/> </s:layout> <s:Rect> .... </s:Rect> <s:Button ... /> <s:Button ... /></s:SkinnableContainer>s
尽管有人会说这只会将事情弄得更复杂,但是从事企业级项目的人都会由衷地感激这个主要的架构设计变化,因为它进一步分离和抽象具体组件类型的功能,从而允许进一步定制。
清单 2 中的代码演示了 Spark 库中的 Panel 组件仅仅是扩展了 SkinnableContainer 基类。有一点值得注意,在 Spark 库中,SkinnableContainer 类是 Group 基类的一个扩展,Group 基类也可以按照在 Flex 3 中扩展 UiComponent 的方法进行扩展。
清单 2. Spark Panel 组件的 Flex 4 SDK 代码
public class Panel extends SkinnableContainer { // The content and layout properties are inherited from SkinnableContainer. // Panel doesn't add much other functionality beyond what's in SkinnableContainer [SkinPart(required="true")] /** * The skin part that defines the appearance of the * title text in the container. */ public var titleField:TextGraphicElement; /** * Title or caption displayed in the title bar. */ public var title:String; // This function is called when the skin part is loaded and assigned. override protected function partAdded(partName:String, instance:*):void { // Assign the content to the header and footer. The main content // assignment is done in the superclass (SkinnableContainer) super.partAdded(partName, instance); if (instance == titleField) { titleField.text = title; } }}
使用 FXG 格式
Flash Catalyst
新的 Adobe Flash Catalyst beta 可以从 Adobe Labs 获取,这使得设计者可以轻松地在组件的不同状态之间创建视觉区别和过渡。设计者可以将创建这些的视觉区别和过渡导出为 FXG 文件,该文件可以集成到您的 Flex 4 项目中。
Adobe Flash XML Graphics (FXG) 是一种在 Flex 应用程序中定义图形的声明语法。Adobe 的 livedocs 技术文档指出:“ FXG 是一种在支持它的应用程序之间互换图形的基于 XML 的语言。”
通过使用 FXG 来简化应用程序开发工作流,您可以利用 FXG 的威力。例如,设计者可以从 Adobe Photoshop® CS4、Illustrator® CS4、Fireworks® CS4 或 Flash Catalyst beta 导出一个 FXG 文档,而导出的代码可以直接用于 Flex 4 应用程序。FXG 通常用于 Spark 皮肤,绘制 skin 类的视觉组件。您可以以内联或定制组件的方式使用 FXG 语法。清单 3 的代码示例演示了如何向 Spark 皮肤添加 FXG 语法。
清单 3. 将 FXG 用于 Spark 皮肤
<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:mx="library://ns.adobe.com/flex/halo"xmlns:s="library://ns.adobe.com/flex/spark" height="200" width="200"> <s:layout> <s:HorizontalLayout/> </s:layout> <s:SkinnableContainer id="myContainer" height="200" width="200" > <s:Button label="Click Me" skinClass="skins.FXGButtonSkin"/> </s:SkinnableContainer></s:Application>
清单 4 中的代码演示了如何将 FXG 皮肤用作自定义组件。这种方法是首选的实现方法,因为 Flex 编译器能够优化 FXG 代码。
清单 4. 将 FXG 皮肤作为自定义组件
<?xml version="1.0" encoding="utf-8"?><s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:ai="http://ns.adobe.com/ai/2008" xmlns:d="http://ns.adobe.com/fxg/2008/dt" minWidth="21" minHeight="21"> <fx:Metadata> [HostComponent("spark.components.Button")] </fx:Metadata> <s:states> <s:State name="up"/> <s:State name="over"/> <s:State name="down"/> <s:State name="disabled"/> </s:states>
<!-- FXG exported from Adobe Illustrator. --> <s:Graphic version="1.0" viewHeight="30" viewWidth="100" ai:appVersion="14.0.0.367" d:id="1"> <s:Group x="-0.296875" y="-0.5" d:id="2" d:type="layer" d:userLabel="Layer 1"> <s:Group d:id="3"> <s:Rect x="0.5" y="0.5" width="100" height="30" ai:knockout="0"> <s:fill> <s:LinearGradient x="0.5" y="15.5" scaleX="100" rotation="-0"> <s:GradientEntry color="#ffffff" ratio="0"/> <s:GradientEntry ratio="1"/> </s:LinearGradient> </s:fill> <s:stroke> <s:SolidColorStroke color="#0000ff" caps="none" weight="1" joints="miter" miterLimit="4"/> </s:stroke> </s:Rect> < /s:Group> </s:Group> </s:Graphic> <s:SimpleText id="labelElement horizontalCenter="0" verticalCenter="1" left="10" right="10" top="15" bottom="2"> </s:SimpleText> </s:SparkSkin>
使用 FXG 的第三种方法是像载入组件一样载入它。
清单 5. 按照载入组件的方法载入 FXG
<?xml version="1.0" encoding="utf-8"?><s:Graphic xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark"> <s:Rect id="rect1" width="200" height="200" > <s:fill> <s:SolidColor color="0xFFFFCC" /> </s:fill> <s:stroke> <s:SolidColorStroke color="0x660099" weight="2" /> </s:stroke> </s:Rect></s:Graphic>
FXG 组件的代码与 MXML 组件的代码类似。
清单 6. FXG 组件的代码
<?xml version="1.0"?> <!-- Set title of the Panel container based on the view state.--> <s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark" title="Login" title.Register="Register"> <!-- The states property defines the view states.--> <s:states> <s:State name="Login"/> <s:State name="Register"/> </s:states> <mx:Form id="loginForm"> <mx:FormItem label="Username:"> <s:TextInput/> </mx:FormItem> <mx:FormItem label="Password:"> <s:TextInput/> </mx:FormItem> <!-- Add a TextInput control to the form for the Register view state. --> <mx:FormItem id="confirm" label="Confirm:" includeIn="Register"> <s:TextInput/> </mx:FormItem> <mx:FormItem direction="horizontal"> <!-- Use the LinkButton to change to the Register view state.--> <!-- Exclude the LinkButton from the Register view state.--> <mx:LinkButton id="registerLink" includeIn="Login" label="Need to Register?" click="currentState='Register'"/> <!-- Add a LinkButton to the form for the Register view state. --> <mx:LinkButton label="Return to Login" includeIn="Register" click="currentState=''"/> <mx:Spacer width="100%" id="spacer1"/> <!-- Set label of the control based on the view state.--> <s:Button id="loginButton" label="Login" label.Register="Register" /> </mx:FormItem> </mx:Form> </s:Panel>
理解下面这一点很重要:FXG 对 MXML 的作用与 CSS 对 HTML 的作用相似,但相比之下,前者的作用大得多。CSS 的许多限制并不存在于 FXG。尽管对 FXG 和 CSS 进行比较似乎有点奇怪,但 FXG 完成的任务在概念上与 CSS 完全相同:它将布局代码和样式信息分离开来。
在 Flex 4 中处理状态
软件即服务企图在本地运行的软件和远程运行(即 “在云中”)的软件之间的缺口上架起一道桥梁。因此,SaaS 应用程序总是要求开发自定义组件。
Flex SDK V2.0 引入了视图状态。这对于向企业级开发引入 Flex 框架发挥了重要作用。Flex 具有开发带有多个 UI 的有状态应用程序并远程运行该程序的能力,这使得它比编写无状态 Web 界面程序的传统方法更具吸引力。
但还有一个问题:应用程序现在是有状态的了,但在一个 Flex 应用程序的不同状态间导航仍旧更像在一个站点的不同页面之间浏览,而不太像处理从本地硬盘运行的应用程序。最重要的是,要清晰了解存在于应用程序的不同状态中的组件之间的通信应该采用的 “恰当” 设计样式,否则在许多情况下将导致一些复杂问题,从而不能在期限内完成项目。结果是带有部分瑕疵的企业 RIA 开发,这种情况通常称为 “未经证明的技术”。
Flex 团队能够认识到这个缺口,主要归功于社区的反馈,这强调了开源技术的价值。最终结果是 Flex 4 中的新的状态引擎和 RIA 开发中的一个重大进步。这也许是一种大胆的宣言,但现在组件负责管理自己的状态,进一步与它们的父程序分离。
清单 7 中的示例演示了一个任意级别的父程序如何控制其子组件的状态。
清单 7. 控制一个子组件的状态
<?xml version="1.0" encoding="utf-8"?><s:Application backgroundColor="0xFFFFFF" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:comps="comps.*"> <comps:GraphicComp id="graphic1"/></s:Application>
清单 8 展示了声明这个组件的代码。
清单 8. 声明组件
<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:MyComp="myComponents.*"> <s:layout> <s:VerticalLayout/> </s:layout> <s:SimpleText text="Login or Register" fontSize="14" fontWeight="bold"/> <MyComp:LoginComponent currentState="Login"/></s:Application>
动画、效果和 3-D
Spark 库还包含针对用户体验设计倡议的重大更新。考虑到新效果集合的大小,Spark 效果根据实现、目标类型(为了更好的管理性)和未来的可伸缩性划分为几个类别。这些类别包括:
属性效果 变形效果 像素明暗器效果 滤镜效果 3-D 效果
属性效果
如您所料,属性效果修改一个目标的一个或多个属性。为此,对需要动画的每个属性声明一个 Animate 类。所有的效果声明必须在 <fx:Declarations/> 标记中进行,这将告知 Flex 编译器,您所做的声明不是可见的显示对象而是行为,这些行为可能会,也可能不会影响应用程序中的一个或多个可见对象。注意,如果您使用 <s:Animate/> 类,则必须在每个 <Animate> 标记内包含 SimpleMotionPath 类的一个实例。这个类别还包含 Fade、Resize 和 AnimateColor 类型的效果。
变形效果
变形效果区别于属性效果的主要特征是,它使平行效果很好地同时播放。因此,如果您的效果相互冲突,导致随意行为(就像在 Flex 3 中一样),您不必寻找另外的解决方法。这个类别促使在一个给定显示对象的相同或相关属性上平行操作的多个效果融合在一起,从而使该对象形成更真实的 “变形”。只要发挥一点想象力,您就可以找到一些独特的方法来实现这个类别中的效果,创建与其他 Flex 应用程序不同的过渡用户体验。清单 9 提供变形效果的一个示例。
清单 9. 变形效果示例
<?xml version="1.0"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark"> <fx:Declarations> <s:Parallel id="parallelRMForward" target="{myImage}"> <s:Rotate angleBy="180"/> <s:Move xBy="100" yBy="100"/> </s:Parallel> <s:Parallel id="parallelRMBack" target="{myImage}"> <s:Rotate angleBy="180"/> <s:Move xBy="-100" yBy="-100"/> </s:Parallel> </fx:Declarations> <s:Button label="Play Effect Forward" x="10" y="10" click="parallelRMForward.end();parallelRMForward.play();"/> <s:Button label="Play Effect Backward" x="150" y="10" click="parallelRMBack.end();parallelRMBack.play();" /> <mx:Image id="myImage" x="10" y="50" source="@Embed(source='assets/logo.jpg')"/></s:Application>
像素明暗器效果
内置的 Spark 像素明暗器效果,CrossFade 和 Wipe,使用它们自己的内部像素明暗器。这种效果的工作方式是,捕获一个 “之前” 和 “之后” 位图,然后混合两个位图,直到最后只有 “之后” 位图可见。像素明暗器效果的一个很酷的功能是您可以使用 Adobes Pixel Bender 工具创建自定义像素明暗器效果,然后在您的 Flex 应用程序中使用它们。清单 10 演示了内置 Wipe 效果的使用方法。
清单 10. Wipe 效果
<?xml version="1.0"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:s="library://ns.adobe.com/flex/spark"> <s:layout> <s:VerticalLayout/> </s:layout> <!-- Define two view states.--> <s:states> <s:State name="default"/> <s:State name="red"/> </s:states> <!-- Define the transition that applies the Wipe effect whenever the view state changes.--> <s:transitions> <s:Transition fromState="*" toState="*"> <s:Sequence target="{myB}"> <s:Wipe id="wipeEffect" direction="right" duration="1000"/> </s:Sequence> </s:Transition> </s:transitions> <s:Button id="myB" label="Wipe" color="black" color.red="red"/> <!-- Define two buttons to change the view state. --> <s:Button label="Set Default State" click="currentState='default'"/> <s:Button label="Set Red State" click="currentState='red'"/></s:Application>
滤镜效果
滤镜效果区别其他效果的一个主要特征是动画的属性是一个 Filter 对象,而不是动画显示对象的一个属性。您使用 AnimateFilter 类动画滤镜的属性。声明 AnimateFilter、目标显示对象、重复计数、期间之后,就可以声明即将操作的确切滤镜了。清单 11 中的示例演示如何创建一个动画的 DropShadowFilter。
清单 11. 动画的 DropShadowFilter
<fx:Declarations> <s:DropShadowFilter id="myDSF" color="0x0000FF" distance="5" angle="315"/> <s:AnimateFilter id="myFilter" target="{myB2}" repeatCount="0" duration="500" repeatBehavior="reverse" bitmapFilter="{new spark.filters.DropShadowFilter()}"> <s:SimpleMotionPath property="color" valueFrom="0" valueTo="0x0000FF"/> <s:SimpleMotionPath property="distance" valueFrom="0" valueTo="10"/> <s:SimpleMotionPath property="angle" valueFrom="270" valueTo="360"/> </s:AnimateFilter></fx:Declarations>
3-D 效果
相比而言,Spark 3-D 效果无法与专用开源 3-D Adobe ActionScript 库(比如 Papervision3D、Away3D 和 Sandy3D)相提并论。但是,这些原生的 3-D 效果是一个很好的出发点,展示了 Adobe 的确有兴趣在 Flash 平台实现 3-D 效果。Spark 3-D 效果包括 Move3D、Rotate3D 和 Scale3D。清单 12 使用 Rotate3D 效果,每一种 3-D 效果都可以使用清单 12 中的方法实现。
清单 12. 使用原生 3-D 效果
<?xml version="1.0" encoding="utf-8"?> <s:Application name="Rotate3D Tester" xmlns="http://ns.adobe.com/mxml/2009"> <layout> <BasicLayout /> </layout> <fx:Declarations> <s:Rotate3D id="x_rotate3d" target="{image}" xFrom="0" xTo="360" duration="2000" /> <s:Rotate3D id="y_rotate3d" target="{image}" yFrom="0" yTo="360" duration="2000" /> <s:Rotate3D id="z_rotate3d" target="{image}" zFrom="0" zTo="360" duration="2000" /> </fx:Declarations> <s:VGroup id="vGroup" left="10" top="10"> <s:Button id="btnX" label="Rotate3D X-axis" click="x_rotate3d.play();" /> <s:Button id="btnY" label="Rotate3D Y-axis" click="y_rotate3d.play();" /> <s:Button id="btnZ" label="Rotate3D Z-axis" click="z_rotate3d.play();" /> </s:VGroup> <mx:Image id="image" source="@Embed('assets/image.jpg')" horizontalCenter="0" verticalCenter="0" width="100" height="100" /></s:Application>
新的文本引擎
Adobe Flash Player 10 包含一个新的文本引擎,进一步支持包含多语言功能和打印的增强功能。Flex 4 框架包含一套新的文本类,比如 RichText 和 SimpleText。Adobe Labs 的 Text Layout Framework 的集成完成将带来最大的改进,这个时间大约在该框架完成测试并对公众发布之前。Text Layout Framework 旨在允许您利用内置于 Flash Player 10 的文本引擎。
使 SaaS 更像一个本地桌面应用程序的一个巨大改进是文本编辑时标准的键盘和鼠标操作,比如剪切、复制、粘贴和撤销。SaaS 还包括丰富的印刷控制,比如字距调整、连字、印刷大小写,以及对 30 多种多语言书写系统的支持。最重要的是,这个文本引擎包括丰富的开发人员 API 来操纵文本内容和布局,标记和创建自定义文本组件。新文本引擎中的三个主要文本基元是 SimpleText、RichText 和 RichEditableText。
基本 HTML 标记支持、行内图形、链接的容器和内置的超链接是 Flex 4 SDK 中最热门的文本渲染新功能。默认的 Spark TextInput 和 TextArea 组件使用 RichEditableText 来提供可编辑的文本区域,因此这些常用的组件的功能比以前更加强大。清单 13 提供了一个简单的示例,展示了 RichText 组件的功能。
清单 13. 使用 Spark 的 RichText 组件的新特性
<s:RichText fontSize="12"> <s:content> <s:TextFlow color="0x222222"> <s:p> <s:span fontWeight="bold">Hello </span> <s:spanv World</s:span> </s:p> </s:TextFlow> </s:content></s:RichText>
结束语
现在已经得出明确的结论,SaaS 的成功与用户体验设计紧密相关。此外,您已经了解了致力于改善用户体验的 Flex 4 SDK 的许多新功能,通过学习如何创建高级 SaaS 应用程序大大提高了自己的技能。RIA 和 SaaS 几乎完全相同,两者都被认定为新一代的人机交互。专家们认为,IT 行业将继续沿着这个方向发展,这也是完全正确的。考虑到这一点,我建议您继续提高您的 RIA 开发技能。