为移动设备应用程序创建外观
自定义移动设备外观时,可以创建自定义的移动设备外观类。在某些情况下,也可以编辑移动设备外观类所使用的资源。
编辑移动设备外观类时,可以更改基于状态的交互,实现对新样式的支持,或者在外观中添加或删除子组件。通常可以从现有外观的源代码入手,将其保存为新类。
并非移动设备外观的所有可视属性都在 *.fxg 文件中定义。例如,Button 外观的背景色由 ButtonSkin 类中的 chromeColor 样式属性定义,而不是在 FXG 资源中定义。在这种情况下,需要编辑外观类来更改背景颜色。
创建移动设备外观类
创建自定义移动设备外观类时,最简单的方法是使用现有移动设备外观类作为基础。然后更改该类,并将其用作自定义外观。
-
在项目中创建目录(例如 customSkins)。此目录的名称是自定义外观的包名称。尽管不需要创建包,但建议您将自定义外观放在单独的包中。
-
在新目录中创建自定义外观类。可根据需要为新类命名,例如 CustomButtonSkin.as。
-
复制新类所基于的外观类的内容。例如,如果正在使用 ButtonSkin 作为基类,请将 spark.skins.mobile.ButtonSkin 文件的内容复制到新的自定义外观类中。
-
编辑新类。例如,至少对 CustomButtonSkin 类进行以下更改:
-
更改包的位置:
package customSkins //was: package spark.skins.mobile
-
在类声明中更改类的名称。它是对新外观所基于的类的扩展(而不是基本外观类):
public class CustomButtonSkin extends ButtonSkin // was: public class ButtonSkin extends ButtonSkinBase
-
更改构造函数中的类名称:
public function CustomButtonSkin() //was: public function ButtonSkin()
-
-
更改自定义外观类。例如,添加对其它状态或新的子组件的支持。此外,外观类本身也定义了一些图形资源,因此可以更改某些资源。
为使外观类更易于理解,通常可以从自定义外观中删除任何不会被重写的方法。
以下自定义外观类扩展了 ButtonSkin,并使用自定义逻辑来替换 drawBackground() 方法。它使用径向渐变替换线性渐变来完成背景填充。package customSkins { import mx.utils.ColorUtil; import spark.skins.mobile.ButtonSkin; import flash.display.GradientType; import spark.skins.mobile.supportClasses.MobileSkin; import flash.geom.Matrix; public class CustomButtonSkin extends ButtonSkin { public function CustomButtonSkin() { super(); } private static var colorMatrix:Matrix = new Matrix(); private static const CHROME_COLOR_ALPHAS:Array = [1, 1]; private static const CHROME_COLOR_RATIOS:Array = [0, 127.5]; override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void { super.drawBackground(unscaledWidth, unscaledHeight); var chromeColor:uint = getStyle("chromeColor"); /* if (currentState == "down") { graphics.beginFill(chromeColor); } else { */ var colors:Array = []; colorMatrix.createGradientBox(unscaledWidth, unscaledHeight, Math.PI / 2, 0, 0); colors[0] = ColorUtil.adjustBrightness2(chromeColor, 70); colors[1] = chromeColor; graphics.beginGradientFill(GradientType.RADIAL, colors, CHROME_COLOR_ALPHAS, CHROME_COLOR_RATIOS, colorMatrix); // } graphics.drawRoundRect(layoutBorderSize, layoutBorderSize, unscaledWidth - (layoutBorderSize * 2), unscaledHeight - (layoutBorderSize * 2), layoutCornerEllipseSize, layoutCornerEllipseSize); graphics.endFill(); } } }
-
在应用程序中,通过应用自定义移动设备外观中介绍的一种方法应用自定义外观。下面的示例使用组件标签上的 skinClass 属性来应用 customSkins.CustomButtonSkin 外观。
<?xml version="1.0" encoding="utf-8"?> <!-- mobile_skins/views/CustomButtonSkinView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="Home"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <s:Button label="Click Me" skinClass="customSkins.CustomButtonSkin"/> </s:View>
移动设备外观的生命周期方法
-
createChildren() — 创建外观所需的任何子图形或文本对象。
-
commitProperties() — 必要时将组件数据复制到外观中。
-
measure() — 尽可能有效地测量外观,并将结果存储在外观的 measuredWidth 和 measuredHeight 属性中。
-
updateDisplayList() — 设置图形和文本的位置和大小。执行任何所需的 ActionScript 绘制。此方法对外观调用 drawBackground() 和 layoutContents() 方法。
有关这些方法使用方法的更多信息,请参阅 Implementing the component。
常用的移动设备外观自定义方法
-
layoutContents() — 确定外观子代(例如投影和标签)的位置。移动设备外观类不支持 HorizontalLayout 和 VerticalLayout 等 Spark 布局。可以在 layoutContents() 等方法中手动布置外观的子代。
-
drawBackground() — 呈示外观的背景。通常情况下,其用途包括绘制 chromeColor、backgroundColor 或 contentBackgroundColor 样式,具体取决于外观的形状。它还可以用于着色,例如使用 applyColorTransform() 方法。
-
commitCurrentState() — 定义移动设备外观的状态行为。可以通过编辑此方法,来添加或删除支持的状态,或者更改现有状态的行为。当状态改变时调用此方法。大多数外观类都会重写此方法。有关更多信息,请参阅移动设备外观状态。
创建自定义 FXG 资源
移动设备外观的大多数可视资源都使用 FXG 进行定义。FXG 是一种声明性语法,用于定义静态图形。可以使用图形工具(如 Adobe Fireworks、Adobe Illustrator 或 Adobe Catalyst)导出 FXG 文档。然后可以在移动设备外观中使用该 FXG 文档。也可以在文本编辑器中创建 FXT 文档,但从头编写复杂的图形非常困难。
-
CheckBox_down.fxg
-
CheckBox_downSymbol.fxg
-
CheckBox_downSymbolSelected.fxg
-
CheckBox_up.fxg
-
CheckBox_upSymbol.fxg
-
CheckBox_upSymbolSelected.fxg
如果在图形编辑器中打开这些文件,将显示如下内容:
适用于多种分辨率的 FXG 文件
大多数移动设备外观都有三组 FXG 图形文件,每一组对应一个默认目标分辨率。例如,所有六个 CheckBoxSkin 类的不同版本位于 spark/skins/mobile160、spark/skins/mobile240 和 spark/skins/mobile320 目录中。
-
使用一个默认外观作为基础(分辨率通常为 160 DPI)。添加外观缩放逻辑,以通过设置 Application 对象的 applicationDPI 属性来根据运行应用程序的设备缩放自定义外观。
-
创建三种版本的自定义外观(160、240 和 320 DPI)以优化显示效果。
某些移动设备外观为其图像资源使用一组 FXG 文件,而不具有特定于 DPI 的图形。这些资源存储在 spark/skins/mobile/assets 目录下。例如,ViewMenuItem 外观和 TabbedViewNavigator 按钮栏外观不具有特定于 DPI 的版本,因此其所有 FXG 资源都存储在此目录下。
自定义 FXG 文件
可以打开现有的 FXG 文件并对其进行自定义,或者在图形编辑器(例如 Adobe Illustrator)中创建并导出 FXG 文件。编辑 FXG 文件后,将其应用到外观类。
-
创建自定义外观类并将其放在 customSkins 目录下,如创建移动设备外观类中所述。
-
在 customSkins 目录下创建一个子目录,例如 assets。创建子目录是可选步骤,但有助于组织 FXG 文件和外观类。
-
在 assets 目录下创建一个文件,并将现有 FXG 文件的内容复制到该文件中。例如,创建名为 CustomCheckBox_upSymbol.fxg 的文件。将 spark/skins/mobile160/assets/CheckBox_upSymbol.fxg 内容复制到新建的 CustomCheckBox_upSymbol.fxg 文件中。
-
更改新的 FXG 文件。例如,使用以渐变项填充的“X”号替换复选标记的绘制逻辑:
<?xml version='1.0' encoding='UTF-8'?> <!-- mobile_skins/customSkins/assets/CustomCheckBox_upSymbol.fxg --> <Graphic xmlns="http://ns.adobe.com/fxg/2008" version="2.0" viewWidth="32" viewHeight="32"> <!-- Main Outer Border --> <Rect x="1" y="1" height="30" width="30" radiusX="2" radiusY="2"> <stroke> <SolidColorStroke weight="1" color="#282828"/> </stroke> </Rect> <!-- Replace check mark with an "x" --> <Group x="2" y="2"> <Line xFrom="3" yFrom="3" xTo="25" yTo="25"> <stroke> <LinearGradientStroke caps="none" weight="8" joints="miter" miterLimit="4"> <GradientEntry color="#FF0033"/> <GradientEntry color="#0066FF"/> </LinearGradientStroke> </stroke> </Line> <Line xFrom="25" yFrom="3" xTo="3" yTo="25"> <stroke> <stroke> <LinearGradientStroke caps="none" weight="8" joints="miter" miterLimit="4"> <GradientEntry color="#FF0033"/> <GradientEntry color="#0066FF"/> </LinearGradientStroke> </stroke> </stroke> </Line> </Group> </Graphic>
-
在自定义外观类中,导入新 FXG 类,并将其应用到某个属性。例如,在 CustomCheckBox 类中:
-
导入新的 FXG 文件:
//import spark.skins.mobile.assets.CheckBox_upSymbol; import customSkins.assets.CustomCheckBox_upSymbol;
-
将新资源添加到自定义外观类中。例如,更改 upSymbolIconClass 属性的值以指向新的 FXG 资源:
upSymbolIconClass = CustomCheckBox_upSymbol;
-
完整的自定义外观类如下所示:
// mobile_skins/customSkins/CustomCheckBoxSkin.as package customSkins { import spark.skins.mobile.CheckBoxSkin; import customSkins.assets.CustomCheckBox_upSymbol; public class CustomCheckBoxSkin extends CheckBoxSkin { public function CustomCheckBoxSkin() { super(); upSymbolIconClass = CustomCheckBox_upSymbol; // was CheckBox_upSymbol } } }
有关处理和优化外观 FXG 资源的信息,请参阅 Optimizing FXG。
在应用程序中查看 FXG 文件
由于 FXG 文件以 XML 编写,因此很难直观看到最终产品的效果。可以编写一个 Flex 应用程序,通过将 FXG 文件添加为组件并封装在 Spark 容器中,来导入和呈示 FXG 文件。
要将 FXG 文件作为组件添加到应用程序中,请将源文件的位置添加到应用程序的源路径中。例如,要在基于 Web 的应用程序中显示移动设备 FXG 资源,请在源路径中添加移动设备主题。然后,编译器即可找到该 FXG 文件。
<?xml version="1.0"?> <!-- mobile_skins/ShowCheckBoxSkins.mxml --> <s:Application 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:skins160="spark.skins.mobile160.assets.*" xmlns:skins240="spark.skins.mobile240.assets.*" xmlns:skins320="spark.skins.mobile320.assets.*"> <s:layout> <s:VerticalLayout/> </s:layout> <!-- NOTE: You must add the mobile theme directory to source path to compile this example. For example: mxmlc -source-path+=\frameworks\projects\mobiletheme\src\ ShowCheckBoxSkins.mxml --> <s:Label text="160 DPI" fontSize="24" fontWeight="bold"/> <s:HGroup> <skins160:CheckBox_down/> <skins160:CheckBox_downSymbol/> <skins160:CheckBox_downSymbolSelected/> <skins160:CheckBox_up/> <skins160:CheckBox_upSymbol/> <skins160:CheckBox_upSymbolSelected/> </s:HGroup> <mx:Spacer height="30"/> <s:Label text="240 DPI" fontSize="24" fontWeight="bold"/> <s:HGroup> <skins240:CheckBox_down/> <skins240:CheckBox_downSymbol/> <skins240:CheckBox_downSymbolSelected/> <skins240:CheckBox_up/> <skins240:CheckBox_upSymbol/> <skins240:CheckBox_upSymbolSelected/> </s:HGroup> <mx:Spacer height="30"/> <s:Label text="320 DPI" fontSize="24" fontWeight="bold"/> <s:HGroup> <skins320:CheckBox_down/> <skins320:CheckBox_downSymbol/> <skins320:CheckBox_downSymbolSelected/> <skins320:CheckBox_up/> <skins320:CheckBox_upSymbol/> <skins320:CheckBox_upSymbolSelected/> </s:HGroup> <s:Label text="down, downSymbol, downSymbolSelected, up, upSymbol, upSymbolSelected"/> </s:Application>
在自定义移动设备外观中使用文本
要在移动设备外观中呈示文本,请使用 StyleableStageText 或 StyleableTextField 类。这些文本类已针对移动设备应用程序进行了优化。
StyleableStageText 允许 TextInput 和 TextArea 控件访问本机文本输入。它扩展了 UIComponent 类,实现了 IEditableText 和 ISoftKeyboardHintClient 接口。
当您不需要访问本机输入时,StyleableTextField 也可由 TextInput 和 TextArea 控件使用。它也可由非输入文本控件(如 ActionBar 和 Button)使用。它扩展了 TextField 类,并可以实现 ISimpleStyleClient 和 IEditableText 接口。
有关在移动设备应用程序中使用文本控件的更多信息,请参阅在移动设备应用程序中使用文本。
移动设备外观中的 TLF
出于性能方面的考虑,在移动设备外观中应尽量避免出现使用 TLF 的类。在某些情况下(例如对于 Spark Label 组件),可以出现使用 FTE 的类。
移动设备外观中的 htmlText
不能在移动设备应用程序中使用 htmlText 属性。
针对文本的手势
触摸加拖动的手势始终会选择文本(如果该文本可以选择或编辑)。如果文本位于 Scroller 中,则只有在文本组件之外做出该手势时,Scroller 才会滚动。只有在文本可以编辑或选择时,这些手势才会生效。
使文本可供编辑和选择
textDisplay.editable = true; textDisplay.selectable = true;
双方向性
在 StyleableStageText 或 StyleableTextField 类中,文本不支持双方向性。