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。