http://www.infoq.com/cn/vendorcontent/show.action?vcr=1168
将应用程序从Flex 3迁移至Flex 4
公司: Adobe
要求
必备知识
熟悉 Adobe Flex。
用户级别
中级
所需产品
在本指南中,我将介绍如何将一个实际应用程序从 Flex 3 迁移至 Flex 4。文中提供的示例涵盖了 Flex 应用程序开发的所有重要领域,包括 CSS、Spark 组件、自定义外观、嵌入字体等。
在您自己动手之转换之前,这看起来好像是一项艰巨的任务。如果您阅读了本指南之后,您就会发现Flex 4在组件架构、CSS改进、新状态机制和新图形标记语言FXG等各方面的优势。MX组件的向后兼容性和Flash Builder 4的优化都让这个转化过程变的简单易行
本指南中使用的示例文件包括原始 Flex 3 应用程序及转换后的 Flex 4 应用程序的源代码。完成指南中所述步骤后,您就可以使用完成后的 Flex 4 应用程序源代码进行引用了。
本文包含以下内容:
- 打开项目
- 命名空间更改
- 警告清除
- 更新应用程序及其背景
- 布局和样式
- 从 ViewStack 到 Flex 4 States
- 添加渐变效果
- 转换 SampleMicPanel 自定义视图
- 转换 PitchDetection 自定义视图
- 转换 InformationPanel 自定义视图
- 转换 InputDeviceSelector 自定义视图
打开项目
首先,打开 Flex 3 项目,将设置更改为指向 Flex 4.1 SDK。我将简要介绍重新对其进行编译所需改变,以及不使用MX兼容模式时Flex4的视觉效果。
- 将 flex3_to_flex4_transitioning.zip 内的 MicrophoneExamplesFlex3.zip 示例文件解压至您选择的文件夹。
- 在 Flash Builder 4 中选择 File -> Import -> Flash Builder Project。
- 选择 Project Folder。
- 单击 Browse,导航至刚才解压的 MicrophoneExamplesFlex3 文件夹,并单击 OK。
- 单击 Finish。
原始项目使用 Flex 3.2 SDK(AIR 2.0 beta 将其覆盖)。如果要构建项目,您将会在 Problems 面板中看到一个错误提示信息“Unknown Flex SDK: …”。要解决这一问题,您需要更改该项目使用的 SDK 版本。
- 下载和安装包含 AIR 2.0 的 Flex 4.1 SDK。(请参阅安装说明中的发布说明。)
- 右键单击项目并选择属性以打开属性对话框。
- 选择左边的 Flex Compiler 类别。
- 在 Flex SDK Version 部分,选择 Flex 4.1 SDK。
- 单击 OK。
注:如果您使用不同的 Flex 4 和 AIR 2.0 SDK 或 Flex 4.1 版本,请使用 Configure Flex SDKs 并选择合适的 SDK。
因为原始应用程序使用 AIR 2.0 beta 版本,您需要更新应用程序描述符文件中的命名空间。
- 打开 src 文件夹中的 MicrophoneExamples-app.xml 文件并找到下列代码行:
<application xmlns="http://ns.adobe.com/air/application/2.0beta2">
- 删除“beta2”,代码行显示如下:
- 保存更改并构建项目。
应用程序将进行无错误编译(尽管可能会出现一些警告)。
- 选择 Run > Run > MicrophoneExamples并运行
图1和图2显示出Flex3版本和Flex4版本的应用程序的不同:
图 1. 用 Flex 3 SDK 构建的原始应用程序。
图 2. 使用 Flex 4 SDK 构建的应用程序,无任何代码更改。
新旧应用程序的差异是由于新 Flex 4 默认 CSS 和主题值产生的。如果您希望 Flex 4 编译器可以严格兼容旧的 MX 组件,可以在 Flex 项目的 Flex Compiler 对话框中选择“Use Flex 3 compatibility mode”选项。
另外请注意:Flex 4.1 SDK 要求的最低版本播放器是 Flash Player 10。
命名空间更改
迁移过程的第二步是进行命名空间的更改。新命名空间将 MXML 2006 命名空间分为三个部分:fx、s 和 mx。这三个部分分别是 MXML 2009 语言和构造(fx)、Spark 组件(s)和 MX 组件(mx)。
更改命名空间的步骤如下:
- 打开主 MicrophoneExamples.mxml 应用程序文件。
- 删除旧命名空间声明:
xmlns:mx="http://www.adobe.com/2006/mxml"
- 插入新命名空间声明:
xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"
- 保存更改并构建项目。
更改命名空间产生两个错误。
- 定位错误(文件第 24 行和第 25 行附近)并分别将 mx:Style 和 mx:Script 更改为 fx:Style 和 fx:Script。
现在命名空间可以覆盖不同的组件集,两个组件可能名称相同,如 s:Button 和 mx:Button。命名空间的目的是清晰定义不同的组件包;这对于 MXML 及 CSS 文件和样式都很重要。Flex 4 包含对 CSS 的多命名空间支持。
- 打开 embed_assets/stylesheet_common.css 文件,并将 Spark 和 MX 命名空间添加到文件的顶部,如下所示:
@namespace s "library://ns.adobe.com/flex/spark"; @namespace mx "library://ns.adobe.com/flex/mx";
您需要将 MX 命名空间添加到 MX 组件。
- 在 WindowedApplication、Application、Window、ComboBox、Hslider、RadioButton 和 ToolTip 前添加 mx|。
剩余样式是特定样式名称。
这时,您也可以利用时机处理主题颜色编译器警告。
- 将主题颜色更改为 chrome 颜色。
请注意:chrome 颜色并非主题颜色的真实替代,而是为了本文中应用程序之目的。新 Spark 组件默认样式集与 Halo 主题不同。
文件的前几行显示如下:
/** * Common CSS definitions for the Adobe Directory */ @namespace s "library://ns.adobe.com/flex/spark"; @namespace mx "library://ns.adobe.com/flex/mx"; mx|WindowedApplication, mx|Application, mx|Window { /* make app window transparent */ font-family: "Myriad Web"; font-size: 12; font-anti-alias-type:advanced; disabled-overlay-alpha: 0; chrome-color: #444444; color: #AAAAAA; text-roll-over-color: #AAAAAA; text-selected-color: #AAAAAA; }
警告清除
这时,在进行下一步操作之前,您还需要处理一个编译器警告。您将会看到一个警告显示不赞成使用 Application.application 并建议使用 FlexGlobals.topLevelApplication。您无法绑定 FlexGlobals,但是可以采用一种不同的办法,在 InformationPanel.mxml 中创建一个公共的可绑定属性并在 MicrophoneExamples.mxml 中对其进行引用。
- 在 InformationPanel.mxml 中定位下列代码:
<mx:Script> <![CDATA[ import mx.core.Application; ]]> </mx:Script> <mx:Label styleName="titleText" text="CREDITS {Application.application.applicationVersion}" />
- 将上述代码更改为如下新的代码:
<mx:Script> <![CDATA[ [Bindable] public var applicationVersion:String = ""; ]]> </mx:Script> <mx:Label styleName="titleText" text="CREDITS {applicationVersion}" />
- 在 MicrophoneExamples.mxml 中定位下列代码:
<view:InformationPanel id="pnlInfo" width="100%" height="100%" styleName="mainPaddedBox" />
- 添加 applicationVersion 属性:
<view:InformationPanel id="pnlInfo" width="100%" height="100%" styleName="mainPaddedBox" applicationVersion="{applicationVersion}" />
更新应用程序及其背景
主应用程序文件包含组成应用程序的几个组件。在这一部分和下一部分,您将将旧的 MX 组件更改为其 Spark 等效组件并探索对应用程序进行布局和设计样式的新方法。
首先要更改的是主 WindowedApplication 类,其中您将将 mx:WindowedApplication 更新为 s:WindowedApplication。
您还需要更改其他一些属性。需要将布局、showFlexChrome、horizontalScrollPolicy 和 verticalScrollPolicy 等 4 个属性删除。布局属性是 Spark 中的 LayoutBase 类(而不是 String 类),且通常在 MXML 中定义。一个 Spark WindowedApplication 组件的默认布局相当于旧的绝对布局属性。
对于 showFlexChrome,您将希望设置 showStatusBar="false",以删除 Flex 状态栏 chrome(默认情况下,Flex 状态栏 chrome 在 Spark WindowedApplication 组件中是打开的)。
在 Spark 中进行滚动通常是在 Skin 中进行处理的,且对于其组件也同样如此。默认情况下,Spark WindowedApplication 不为应用程序绘制任何 chrome;如果需要,应该开发人员来绘制 chrome。
在原始代码中,使用 VBox 和 mainBox CSS 样式创建一个自定义背景。mainBox 样式仅沿应用程序的宽度和高度提供一个灰色背景。在新应用程序中,它可以从主应用程序中删除 Vbox 组件并从 CSS 文件中删除 mainBox 样式。然后您可以将 backgroundColor="0x666666" 添加到主应用程序类中,以达到同样的效果。
实现上述更改的步骤如下:
- 在 MicrophoneExamples.mxml 中定位下列代码:
<mx:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" showEffect="Fade" hideEffect="Fade" width="460" height="210" showFlexChrome="false" creationComplete="showMain();" horizontalScrollPolicy="off" verticalScrollPolicy="off" layout="absolute" xmlns:view="view.*" viewSourceURL="srcview/index.html">
- 用如下代码更新WindowedApplication组件:
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:view="view.*" showEffect="Fade" hideEffect="Fade" width="460" height="210" creationComplete="showMain();" showStatusBar="false" backgroundColor="0x666666" viewSourceURL="srcview/index.html">
- 通过删除下列行删除 Vbox:
<mx:VBox id="bgBox" width="460" height="210" styleName="mainBox" />
- 将结束标记从 </mx:WindowedApplication> 更改为 </s:WindowedApplication>。
- 从 stylesheet_common.css 中删除 mainBox 定义。
布局和样式
在 Flex 3 中,布局和设置样式的能力(填充、背景颜色等)被混合到一个组件中。将麦克风应用程序(或其他任何应用程序)从 Flex 3 迁移至 Flex 4 时,您会注意到可以独立处理布局和样式的区域。
例如,在 MicrophoneExamples.mxml 中检查首个 Hbox。Hbox 在 Spark 中没有直接的一对一组件匹配,尤其是 titleBox 样式类定义 CSS 文件中的填充、边框和背景值后。在 Spark 中,Group 类被设计为轻量级布局和容器类,但是它们不提供任何外观自定义功能。对于外观自定义功能或任何展示组件,您需要使用一个可以扩展 SkinnableComponent 的类。您可以使用 SkinnableContainer 在容器中展示可视内容和布局元素。这将打开很多选项,并导致些许混乱。
因为 Hbox 提供可视内容和布局,使用 SkinnableContainer 类是个好主意。
以下是所有更改都完成后的 SkinnableContainer;具体步骤见下文。
<s:SkinnableContainer skinClass="controls.skins.TopBarSkin" width="100%"> <s:Group y="8" mouseDown="startMove(event)" mouseUp="movingReferenceEvent = null"> <s:BitmapImage source="@Embed('embed_assets/mic16.png')" /> <s:Label text="MICROPHONE" styleName="titleText" x="18" y="3" backgroundAlpha="0" /> <s:Label id="txtExample" text="{viewName}" x="100" y="3" styleName="titleTextGrey" backgroundAlpha="0" /> </s:Group> <s:HGroup mouseDown="startMove(event)" mouseUp="movingReferenceEvent = null" verticalAlign="bottom" width="100%" horizontalAlign="right" gap="10"> <s:Button styleName="leftArrowButton" click="changeView('left')" /> <s:Button styleName="rightArrowButton" click="changeView('right')" /> <s:ToggleButton id="btnInfo" styleName="helpButton" click="changeView('info')" tabEnabled="false" toolTip="Information" /> <s:Button styleName="appCloseButton" click="stage.nativeWindow.close()" tabEnabled="false" toolTip="Close" /> </s:HGroup> </s:SkinnableContainer>
- 首先在 MicrophoneExamples.mxml 中用 s:SkinnableContainer 代替 mx:Hbox。
- 在名为 controls.skins 的项目中创建一个新包。
- 在该包中,使用一个 spark.components.SkinnableContainer 主机组件创建一个名为 TopBarSkin.mxml 的新 MXML 外观。
- 将下列代码复制到 TopBarSkin.mxml,覆盖其默认内容。>
<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5"> <fx:Metadata> <![CDATA[ [HostComponent("spark.components.SkinnableContainer")] ]]> </fx:Metadata> <s:states> <s:State name="normal" /> <s:State name="disabled" /> </s:states> <s:Rect id="background" width="100%" height="35"> <s:fill> <s:SolidColor color="0x212121" /> </s:fill> </s:Rect> <s:Line width="100%" y="34"> <s:stroke> <s:SolidColorStroke color="0x121212" /> </s:stroke> </s:Line> <s:HGroup id="contentGroup" paddingLeft="10" paddingTop="6" paddingRight="10" paddingBottom="6" horizontalAlign="left" verticalAlign="middle" width="100%" /> </s:Skin>
该外观通过使用 titleBox CSS 样式表中的值绘制一个 Rect 和 Line 来创建背景和底部边框。SkinnableContainer 寻找一个名为 contentGroup 的外观部件,在该外观中是一个 Hgroup,其值是通过 titleBox 样式在原始 Hbox 上使用的填充值和布局值。
在原始 Hbox 内,首个容器是一个包含应用程序麦克风图标和部分标签的 Canvas 组件。其目的仅仅是使用部分特定值部署组件。
- 将 mx:Canvas 更改为 s:Group。
在 Canvas 内,有一个 Image 组件:
<mx:Image source="embed_assets/mic16.png" y="3" />
mx:Image 类支持动态和静态图像加载,但是使用 s:BitmapImage 将更加快速,且使用的类也更小。
- 将 mx:Image 行更改为:
<s:BitmapImage source="@Embed('embed_assets/mic16.png')" />
- 将 mx:Label 组件更改为 s:Label 组件。
此更改还要求对 CSS 文件进行部分更改。Flex 4 Spark 控件使用新的 Flash Player 10 文本布局框架(TLF)展示文本;它更加新(先进)且可以提供几种新功能,包括双向文本。它与嵌入字体的工作方式也不同。在使用 @font-face 嵌入不同字体的 CSS 文件中,您需要添加 embedAsCFF: true;。您还需要为希望使用嵌入字体的特定样式类添加 fontLookup: embeddedCFF;。
- 在 stylesheet_common.css 文件中进行下列更改:
@font-face { src:url("/embed_assets/fonts/MYRIAD.TTF"); font-family: "Myriad Web"; advanced-anti-aliasing: true; embedAsCFF: true; } @font-face { src:url("/embed_assets/fonts/MYRIADB_0.TTF"); font-family: "Myriad Web"; font-weight: bold; advanced-anti-aliasing: true; embedAsCFF: true; } @font-face { src:url("/embed_assets/fonts/MyriadPro-Black.otf"); font-family: "Myriad Pro Black"; embedAsCFF: true; } .titleText, .titleTextGrey, .titleTextBlack { font-size: 12; color: #FFFFFF; font-family: "Myriad Pro Black"; fontLookup: embeddedCFF; }
默认情况下,s:Label 有一个背景颜色,因此您会希望通过用 CSS 文件中的 background-alpha: 0; 添加一个 s|Label CSS 样式使背景颜色不可见。
- 将下列代码添加到 stylesheet_common.css:
s|Label { background-alpha: 0; font-size: 12; }
- 同样,在 Label 组件上添加 y="3" 并将两个像素添加到标签组件的 x 值,以使文本重新排行,因为 TLF 的默认定位:
<s:Label text="MICROPHONE" styleName="titleText" x="18" y="3" backgroundAlpha="0" /> <s:Label id="txtExample" text="{viewName}" x="100" y="3" styleName="titleTextGrey
原始 Hbox 的第二组组件包含右边的 4 个按钮:左导航、右导航、帮助和关闭。
- 容器类 mx:Hbox 不包含任何可视内容,因此将其更改为 s:Hgroup,保留水平布局。同样,将 horizontalGap 属性更改为 gap。
您需要记住 Spark 按钮上的一些更改。您将看到原始 btnInfo 按钮的 toggle 为“真”。默认情况下,Spark 按钮不实现 toggle 功能。有一个选择状态的按钮有一个 Spark ToggleButton。下一个大问题是,在默认情况下,Spark 按钮的风格不支持通过样式进行向上、向下、over 和禁用外观操作。幸运的是这不难处理。您基本想要为按钮状态使用图像,并弃用普通按钮外观的所有绘画,这就是 Flex 4 外观自定义功能中的所有内容。
- 将 mx:Button 组件更改为 s:Button 组件——如果是 btnInfo,则更改为 s:ToggleButton。
- 在 controls.skins 包中创建一个名为 IconButtonSkin 的新 MXML Skin。
- 将下列代码复制到 IconButtonSkin.mxml:
<?xml version="1.0" encoding="utf-8"?> <s:SparkSkin xmlns:fx=http://ns.adobe.com/mxml/2009 xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" currentStateChanging="onCurrentStateChanging(event)"> <fx:Metadata>[HostComponent("spark.components.supportClasses.ButtonBase")]</fx:Metadata> <!-- host component --> <fx:Script fb:purpose="styling"> <![CDATA[ import mx.events.StateChangeEvent; private function onCurrentStateChanging(event:StateChangeEvent):void { switch (event.newState) { case "up": setIcon("upSkin"); break; case "over": setIcon("overSkin"); break; case "down": setIcon("downSkin"); break; case "disabled": setIcon("disabledSkin"); break; case "upAndSelected": setIcon("selectedUpSkin"); break; case "overAndSelected": setIcon("selectedOverSkin"); break; case "downAndSelected": setIcon("selectedDownSkin"); break; case "disabledAndSelected": setIcon("selectedDisabledSkin"); break; } } private function setIcon(type:String):void { if (hostComponent.getStyle(type) != null) { icon.source = hostComponent.getStyle(type); } } ]]> </fx:Script> <!-- states --> <s:states> <s:State name="up" /> <s:State name="over" /> <s:State name="down" /> <s:State name="disabled" /> <s:State name="upAndSelected" /> <s:State name="overAndSelected" /> <s:State name="downAndSelected" /> <s:State name="disabledAndSelected" /> </s:states> <s:BitmapImage id="icon" source="{hostComponent.getStyle('upSkin')}" left="0" right="0" top="0" bottom="0" /> </s:SparkSkin>
该 Skin 文件中的代码侦听状态更改,然后使用状态值根据样式查找设置图标。样式是旧版的 mx:Button 的样式,因此无须更改 CSS 代码。请注意:代码还将检查样式是否存在以确认它没有试图设置一个无效的图像源。IconButtonSkin 不包含任何绘画代码或标签,仅包含一个单独的 s:BitmapImage。该组件的源属性被设置成 CSS 样式中设置的值。
因为该应用程序没有其他按钮,您可以在 CSS 文件中为 s|Button 和 s|ToggleButton 设置默认外观,以新建 IconButtonSkin。
- 将下列代码添加到 stylesheet_common.css:
s|Button, s|ToggleButton { skin-class: ClassReference("controls.skins.IconButtonSkin"); }
现在所有向上、over 和其他状态的特定按钮 CSS 类样式将与新的 s|Button 和 s|ToggleButton 外观文件一起工作。
从 ViewStack 到 Flex 4 states
Flex 4 对 MXML 中状态工作的方式进行了彻底革新,新版方法比旧版方法(使用旧版方法时,所有状态逻辑都在状态 MXML 块中)更加简易。您可以使用 Flex 4 状态机制代替 mx|ViewStack 功能的大部分简单案例。
注:无 Spark ViewStack 直接组件替代,但是如果您需要旧版 selectedChild 属性和相似的语法,您可以从网上找到第三方 ViewStack Flex 4 Spark 组件。
-
要使用新状态方法,请打开 MicrophoneExamples.mxml 并添加三种状态,分别用于 ViewStack 中声明的三种视图:
<s:states> <s:State name="sampleMic" /> <s:State name="pitchDetection" /> <s:State name="info" /> </s:states>
注:<s:states> 块必须放置于任何内容组件之前,否则您将收到下列编译器错误提示:“Child elements of 'WindowedApplication' serving as the default property value for 'mxmlContentFactory' must be contiguous. MicrophoneExamples.mxml /microphone/src line 57 Flex Problem”。
- 接下来,删除 mx:ViewStack 并使用各自的状态名称为 mx:ViewStack 中每个自定义组件添加 includedIn 属性:
<view:SampleMicPanel id="pnlMic" left="0" top="40" right="0" bottom="0" includeIn="sampleMic" micSelector="{micSelector}"/> <view: PitchDetection id="pnlTuner" left="0" top="40" right="0" bottom="0" includeIn="pitchDetection" micSelector="{micSelector}" /> <view:InformationPanel id="pnlInfo" left="0" top="40" right="0" bottom="0" paddingLeft="10" paddingTop="8" paddingRight="10" includeIn="info" applicationVersion="{applicationVersion}" />
- 构建项目。
在 Problems 面板中,您将在 MicrophoneExamplesSource.as 中看到三个错误,分别在下列三行中:
vsMain.selectedChild = pnlInfo; vsMain.selectedChild = pnlMic; vsMain.selectedChild = pnlTuner;
您需要更改这些行上的 currentState,而不是更改 selectedChild。
- 在 MicrophoneExamplesSource.as 中编辑上述所有行,并将这些行更改为:
currentState = "info"; currentState = "sampleMic"; currentState = "pitchDetection";
当 currentState 属性值更改时,触发事件,用于状态转换。以下是 MicrophoneExamplesSource.as 代码更改:
if (view != "info") { btnInfo.selected = false; } else { viewName = "(Application Info)"; currentState = "info"; } if (view == "mic") { viewName = "(Record & Playback)"; currentState = "sampleMic"; } if (view == "tuner") { viewName = "(Pitch Detection)"; currentState = "pitchDetection"; }
添加渐变效果
Flex 4 方法支持状态转换。它们允许您轻松应用状态转换效果。以麦克风为例,您可以为每次状态更改添加一个渐变状态转换。
- 将下列代码添加到 <s:states> 块下的 MicrophoneExamples.mxml:
<s:transitions> <s:Transition toState="pitchDetection"> <s:Fade alphaFrom="0.0" alphaTo="1.0" duration="600" targets="{[pnlTuner,txtExample]}"/> </s:Transition> <s:Transition toState="sampleMic"> <s:Fade alphaFrom="0.0" alphaTo="1.0" duration="600" targets="{[pnlMic,txtExample]}"/> </s:Transition> <s:Transition toState="info"> <s:Fade alphaFrom="0.0" alphaTo="1.0" duration="600" targets="{[pnlInfo,txtExample]}"/> </s:Transition> </s:transitions>
每个自定义视图中的 txtExample 引用与每个视图一起更改的顶部栏内的标签。在应用程序的 Flex 3 版本中,标签无 id,因此您需要添加一个。
- 使用 text="{viewName}" 将 id="txtExample" 添加到应用程序中的 Label:
<s:Label id="txtExample" text="{viewName}" x="100" y="3" styleName="titleTextGrey" backgroundAlpha="0" />
转换 SampleMicPanel 自定义视图
迁移至 Flex 4 的应用程序的最后部分是两个麦克风示例的自定义组件视图和信息面板。每个组件迁移使用相同的基本方法和技巧,且可能看似之前步骤的重复,这将演示代码和外观的部分重用。
以示例 mic 视图开始。
- 打开 SampleMicPanel.mxml 并将主组件从 mx:Canvas 更改为 s:Group,因为在 mx:Canvas 上无样式设计功能。
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:view="view.*" creationComplete="init();" hide="stop()">
- 添加三个新的命名空间:
- 因为新的命名空间更改,将 mx:Script 块更改为 fx:Script。
首个子 mx:Canvas 组件的 styleName 为“controlsBox”。
- 从 CSS 文件中删除 controlsBox 样式。
- 将 Canvas 组件更改为 SkinnableComponent:
<s:SkinnableComponent left="9" right="9" top="50" height="60" skinClass="controls.skins.ControlsBoxSkin" />
- 在 controls.skins 包中创建一个名为 ControlsBoxSkin.mxml 的新 MXML Skin,并将下列代码复制到其中:
<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"> <!-- host component --> <fx:Metadata> [HostComponent("spark.components.supportClasses.SkinnableComponent")] </fx:Metadata> <s:states> <s:State name="normal" /> <s:State name="disabled" /> </s:states> <s:Rect width="100%" height="100%"> <s:stroke> <s:SolidColorStroke color="0x3A3A3A" /> </s:stroke> <s:fill> <s:SolidColor color="0x565656" /> </s:fill> </s:Rect> <s:Group id="contentGroup" left="5" right="5" top="4" bottom="4" /> </s:Skin>
该外观以后将在其他自定义组件中重用。
第二个 mx:Canvas 有一个 id="spectrum",是一个可以动态绘制波形图的占位符。
- 将 mx:Canvas 更改为 s:Group。Group 类扩展了可以按程序绘制的 Sprite。
- 更改代码的 TOP CONTROLS 部分,如下所示:
<!-- TOP CONTROLS --> <s:HGroup id="topControls" left="10" right="10" top="0"> <s:ToggleButton id="btnRecord" click="recordSound()" styleName="recordButton" /> <s:Label styleName="footerPTText" text="{micSelector.micName}" click="micSelector.visible = !micSelector.visible" /> <s:Group width="100%" /> <s:Button id="btnSave" click="savePrompt()" enabled="false" toolTip="Save and Open in Default OS WAV Player" styleName="saveOpenButton" /> </s:HGroup>
在上述代码中,mx:HBox 被更改为 s:Hgroup,mx:Button 被更改为 s:Button 和 s:ToggleButton(删除 toggle 属性),mx:Label 被更改为 s:Label。mx:Spacer 被更改为 s:Group,其中 width="100%"。
- s:Label 填充与 mx:Label 不同,因此编辑 CSS 文件并为 footerPTText 将 padding-top: 2px 更改为 padding-top: 6px。
- 更改代码的 TIMING UI 部分,如下所示:
<!— TIMING UI --> <s:HGroup id="timings" left="10" right="10" top="31" gap="0"> <s:Label styleName="titleTextBlack" text="Last Data Event:" /> <s:Label styleName="footerText" text="{micStats}" /> <s:Group width="100%" /> <s:Label styleName="titleTextBlack" text="Recording Time:" /> <s:Label styleName="footerText" text="{micTimer}" textAlign="right" /> </s:HGroup>
在上述代码中,mx:HBox 被更改为 s:HGroup 且属性 horizontalGap 被更改为 gap。同样,mx:Spacer 被更改为 s:Group,其中 width="100%"。因为填充的不同 s:Hgroup 被降低了五个像素。
- 更改代码的 PLAY CONTROLS 部分,如下所示:
<!-- PLAY CONTROLS --> <s:HGroup id="playControls" left="10" right="10" bottom="30" verticalAlign="middle" gap="2"> <s:ToggleButton styleName="playButton" id="btnPlay" click="isPlayingFlag = true;playRecordedData()" /> <s:Group id="playHeadCanvas" height="16" y="5" width="100%"> <s:Rect width="100%" height="100%"> <s:stroke> <s:SolidColorStroke color="0x3A3A3A" /> </s:stroke> <s:fill> <s:SolidColor color="0xAAAAAA" /> </s:fill> </s:Rect> <s:Group id="playHead" width="8" height="15" y="0" x="0"> <s:Rect width="100%" height="100%"> <s:fill> <s:SolidColor color="0x333333" /> </s:fill> </s:Rect> </s:Group> </s:Group> <s:Group height="100%"> <s:HSlider width="64" dataTipFormatFunction="volumeDataTipFunction" toolTip="Volume" y="7" skinClass="controls.skins.MyHSliderSkin" id="vsVol" minimum="0" maximum="100" value="60" /> </s:Group> </s:HGroup>
在代码的 PLAY CONTROLS 部分,mx:HBox 被更改为 s:Hgroup,mx:Button 被更改为 s:ToggleButton(删除 toggle 属性),所有 mx:Canvas 被更改为 s:Group,mx:HSlider 被更改为 s:Hslider。playHeadCanvas 和 playHead 组件在 mx:Canvas 上设置有背景颜色;它们被删除并用 Rect 组件直接拉入 Group 组件。
注:直接拉至 Spark Group 组件与常规外观自定义操作不同。我在此介绍这种方法主要是为了提供另一种不同的方法。这种方法功能略逊,但是不一定效果差。
s:HSlider 通过外观而非像以前一样通过样式处理 DataTip 样式设置。因此您需要创建一个自定义外观。
- 在 controls.skins 包中创建一个名为 MyHSliderSkin.mxml 的新 MXML Skin,并将代码从完整的 Flex 4 示例文件复制到其中。
为了制作该外观,我创建了一个 Spark Hslider 外观,并将 DataTip 部分微调成圆角深色矩形和淡灰色文本。在 CSS 文件中无等效物,但是 mx:Hslider 将在设置 DataTip 样式时使用通用样式,因此需要在 s:Hslider 的外观中手动进行更改。以下是 MyHSliderSkin.mxml 外观中 DataTip 部分的代码:
<fx:Declarations> <!--- The tooltip used in the mx.controls.Slider control. To customize the DataTip's appearance, create a custom HSliderSkin class.--> <fx:Component id="dataTip"> <s:DataRenderer minHeight="24" minWidth="40" y="-34"> <s:Rect top="0" left="0" right="0" bottom="0" radiusX="2" radiusY="2"> <s:fill> <s:SolidColor color="0x353535" alpha=".9"/> </s:fill> <s:filters> <s:DropShadowFilter angle="90" color="0x000000" distance="2"/> </s:filters> </s:Rect> <s:Label id="labelDisplay" text="{data}" horizontalCenter="0" verticalCenter="1" left="5" right="5" top="5" bottom="5" color="0xdddddd" textAlign="center" verticalAlign="middle" fontWeight="normal" fontSize="11"> </s:Label> </s:DataRenderer> </fx:Component> </fx:Declarations>
注:Hslider、RadioButton 和 ComboBox CSS 样式值使用自定义图像作为图标样式值。对于我之前讨论的 s:Button,我必须通过外观而非样式(或者一个可以读取样式的自定义外观)做到这一点。上述 Spark 组件的默认外观提供我正在寻找的外观和感觉,但是略有不同,因此我没有为那些组件创建自定义外观。方法类似 controls.skins.IconButtonSkin 的方法,但是由于嵌套外观的原因略微复杂一些。
- 继续通过代码的剩余部分,并将相同类型的更改应用于各种组件。如果需要,您可以参阅已完成的示例文件。
将 mx:ComboBox 切换为 s:ComboBox 时需要注意的一点是 dataProvider 不提供 Array 值;它必须是 Ilist。我将 Array 包装到一个实现 IList 的 ArrayList 中。确保使用导入 mx.collections.ArrayList; 将 ArrayList 导入到 Script 块的顶部。代码如下:
<s:Group width="100%" left="10" right="10" top="148"> <s:Label styleName="titleTextBlack" text="Playback Speed:" y="1" /> <s:HSlider id="hsSpeed" left="94" right="0" dataTipFormatFunction="dataTipFunction" toolTip="Speed" value="50" snapInterval="1" minimum="10" maximum="90" liveDragging="true" /> </s:Group> <s:HGroup id="bottomControls" left="10" right="10" bottom="10"> <s:ComboBox id="nmQuality" visible="false" includeInLayout="false" dataProvider="{new ArrayList([2048,(1024*3),(1024*4),(1024*5),(1024*6),(1024*7),8192])}" /> </s:HGroup>
转换 PitchDetection 自定义视图
PitchDetection 自定义视图的更新非常像之前的自定义组件更新,通过添加命名空间和将所有的 MX 组件更改为其 Spark 等效物实现。您需要将主 mx:Canvas 更改为 s:Group,并将 mx:Canvas(styleName="controlsBox")更改为 s:SkinnableContainer(值为 skinClass="controls.skins.ControlsBoxSkin"),如之前的 SampleMicPanel 组件迁移一样。选择一个用于外观重用。下面是 PitchDetection.mxml 内容部分的代码:
<s:ToggleButton id="btnRecord" click="recordSound()" left="10" styleName="recordButton" /> <s:Label styleName="titleTextBlack" text="Start Sampling to Determine the Pitch of the Audio" bottom="6" horizontalCenter="0" /> <s:Label styleName="footerPTText" text="{micSelector.micName}" click="micSelector.visible = !micSelector.visible" y="0" left="50" /> <s:Label id="note_tx" text="Note" verticalCenter="-48" horizontalCenter="0" styleName="titleTextBlack" fontSize="32"/> <s:SkinnableComponent left="15" right="15" bottom="31" height="80" skinClass="controls.skins.ControlsBoxSkin" /> <s:BitmapImage source="@Embed('embed_assets/pitch/musicstaff.png')" left="15" bottom="31" /> <s:BitmapImage source="@Embed('embed_assets/pitch/notedown.png')" verticalCenter="31" horizontalCenter="0" id="notedown" visible="false" /> <s:BitmapImage source="@Embed('embed_assets/pitch/noteup.png')" verticalCenter="16" horizontalCenter="0" id="noteup" visible="false" /> <s:BitmapImage source="@Embed('embed_assets/pitch/noteupwbar.png')" verticalCenter="16" horizontalCenter="-1" id="noteupwbar" visible="false" /> <s:BitmapImage source="@Embed('embed_assets/pitch/sharp.png')" verticalCenter="32" horizontalCenter="-15" id="sharp" visible="false" />
请参阅 PitchDetection.mxml 的示例 Flex 4 版本,以获取完整的示例。
您也可以在 MicrophoneExamples.mxml 文件中从 PitchDetection 组件中删除 styleName="mainPaddedBox",因为该组件不需要且那些样式将不应用于 s:Group 视图的顶部组件。
转换 InformationPanel 自定义视图
在 InformationPanel 组件中,您需要将 mx:VBox 更改为 s:Vgroup,并将 verticalGap 更改为 gap。您可以在 MicrophoneExamples.mxml 文件中从 InformationPanel 组件中删除 styleName="mainPaddedBox",并从主 CSS 文件中删除 mainPaddedBox。这是因为 Spark 组件不是通过样式进行填充的,而是作为 s:VGroup 组件上的属性。将旧版的填充样式值作为 MicrophoneExamples.mxml 文件中声明的 InformationPanel 上的属性(paddingLeft="10" paddingTop="8" paddingRight="10")。
当您将 mx:Label 更改为 s:Label 时,将影响填充及文本的大小,因此您需要将 CSS 文件中的 .infoText 字体大小更改为 12。原始 mx:Hrule 基本是一行,因此您可以删除该组件并用 s:Line(其中厚度重量为 2)将其替换。所有更改都完成后的代码如下:
<?xml version="1.0" encoding="utf-8"?> <s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" gap="8"> <fx:Script> <![CDATA[ [Bindable] public var applicationVersion:String = ""; ]]> </fx:Script> <s:Label styleName="titleText" text="CREDITS {applicationVersion}" /> <s:Line width="100%"> <s:stroke> <s:SolidColorStroke color="0xffffff" weight="2" /> </s:stroke> </s:Line> <mx:Spacer height="0" /> <s:Label styleName="titleTextBlack" text="Application Author: "/> <s:Label styleName="infoText" text="Renaun Erickson" /> <s:Label styleName="titleTextBlack" text="Pitch Detection Code: "/> <s:Label styleName="infoText" text="John Montgomery (psychicorigami.com) AS3 port Benjamin Dobler" /> <s:Label styleName="infoText" text="Modified by Renaun Erickson" /> </s:VGroup>
转换 InputDeviceSelector 自定义视图
InputDeviceSelector 自定义组件利用 controlsBox 样式,这就意味着您可以用 s:SkinnableContainer 重用 controls.skins.ControlsBoxSkin,以代替 mx:Canvas。您还需要像以前一样进行 fx:Script、s:Label 和 s:Vgroup 更改。当您将 mx:ButtonRadioGroup 更改为 s:ButtonRadioGroup 时,需要将其移动到一个新的 fx:Declarations 代码块中,以使其与可视声明相分离。如果您在上述更改后进行编译,将会看到错误提示建议使用 addElement 而非 addChild。Spark 容器组件必须实现 IvisualElement 接口并使用新的 addElement 方法。只需将 vbButtons.addChild 更改为 vbButtons.addElement,以解决编译器错误,这样就全部完成了。下面是该自定义组件的内容部分:
<fx:Declarations> <s:RadioButtonGroup id="grpRadio" itemClick="changeMic(event)" /> </fx:Declarations> <s:Label styleName="infoText" text="Select An Input Device:" left="6" top="6" /> <s:VGroup id="vbButtons" left="6" right="6" top="22" bottom="6" gap="5" />
请参阅 InputDeviceSelection.mxml 的示例 Flex 4 版本,以获取应用程序的完整 example.Run,然后就可以享用了;这就是从 Flex 3 迁移至 Flex 4 的全部过程。
后续工作
应用程序完全是逻辑的,而且迁移应用程序不是一项简单的任务。从 Flex 3 迁移到 Flex 4 的其中一大优势是混合和匹配 MX 和 Spark 组件的能力,这支持您逐步执行应用程序的转移。关于特定 Flex 3 和 Flex 4 组件之间区别的更多信息,请查看 Flex 3 与 Flex 4 之间的区别。如果您正在转换 IDE 及进行迁移,请参阅 将已有 Flex 项目从 Flex Builder 3 迁移至 Flash Builder 4。