为移动设备应用程序创建外观

自定义移动设备外观时,可以创建自定义的移动设备外观类。在某些情况下,也可以编辑移动设备外观类所使用的资源。

编辑移动设备外观类时,可以更改基于状态的交互,实现对新样式的支持,或者在外观中添加或删除子组件。通常可以从现有外观的源代码入手,将其保存为新类。

也可以编辑移动设备外观所使用的资源来更改外观的可视属性,如大小、颜色、渐变和背景。在这种情况下,也可以编辑外观所使用的 FXG 资源。移动设备外观所使用的源 *.fxg 文件位于 spark/skins/mobile/assets 目录下。

并非移动设备外观的所有可视属性都在 *.fxg 文件中定义。例如,Button 外观的背景色由 ButtonSkin 类中的 chromeColor 样式属性定义,而不是在 FXG 资源中定义。在这种情况下,需要编辑外观类来更改背景颜色。

创建移动设备外观类

创建自定义移动设备外观类时,最简单的方法是使用现有移动设备外观类作为基础。然后更改该类,并将其用作自定义外观。

要创建自定义外观类,请执行以下操作:
  1. 在项目中创建目录(例如 customSkins)。此目录的名称是自定义外观的包名称。尽管不需要创建包,但建议您将自定义外观放在单独的包中。

  2. 在新目录中创建自定义外观类。可根据需要为新类命名,例如 CustomButtonSkin.as。

  3. 复制新类所基于的外观类的内容。例如,如果正在使用 ButtonSkin 作为基类,请将 spark.skins.mobile.ButtonSkin 文件的内容复制到新的自定义外观类中。

  4. 编辑新类。例如,至少对 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()
  5. 更改自定义外观类。例如,添加对其它状态或新的子组件的支持。此外,外观类本身也定义了一些图形资源,因此可以更改某些资源。

    为使外观类更易于理解,通常可以从自定义外观中删除任何不会被重写的方法。

    以下自定义外观类扩展了 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();
            }
            
        }
    }
  6. 在应用程序中,通过应用自定义移动设备外观中介绍的一种方法应用自定义外观。下面的示例使用组件标签上的 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>

移动设备外观的生命周期方法

创建自定义外观类时,应熟悉以下 UIComponent 方法。这些继承的、受保护的方法将定义外观的子代和成员,并帮助外观与显示列表中的其它组件进行交互。
  • createChildren() — 创建外观所需的任何子图形或文本对象。

  • commitProperties() — 必要时将组件数据复制到外观中。

  • measure() — 尽可能有效地测量外观,并将结果存储在外观的 measuredWidth  measuredHeight 属性中。

  • updateDisplayList() — 设置图形和文本的位置和大小。执行任何所需的 ActionScript 绘制。此方法对外观调用 drawBackground()  layoutContents() 方法。

有关这些方法使用方法的更多信息,请参阅 Implementing the component

常用的移动设备外观自定义方法

许多移动设备外观都实现以下方法:
  • layoutContents() — 确定外观子代(例如投影和标签)的位置。移动设备外观类不支持 HorizontalLayout 和 VerticalLayout 等 Spark 布局。可以在 layoutContents() 等方法中手动布置外观的子代。

  • drawBackground() — 呈示外观的背景。通常情况下,其用途包括绘制 chromeColorbackgroundColor  contentBackgroundColor 样式,具体取决于外观的形状。它还可以用于着色,例如使用 applyColorTransform() 方法。

  • commitCurrentState() — 定义移动设备外观的状态行为。可以通过编辑此方法,来添加或删除支持的状态,或者更改现有状态的行为。当状态改变时调用此方法。大多数外观类都会重写此方法。有关更多信息,请参阅移动设备外观状态

创建自定义 FXG 资源

移动设备外观的大多数可视资源都使用 FXG 进行定义。FXG 是一种声明性语法,用于定义静态图形。可以使用图形工具(如 Adobe Fireworks、Adobe Illustrator 或 Adobe Catalyst)导出 FXG 文档。然后可以在移动设备外观中使用该 FXG 文档。也可以在文本编辑器中创建 FXT 文档,但从头编写复杂的图形非常困难。

移动设备外观通常使用 FXG 文件来定义外观的状态。例如,CheckBoxSkin 类使用以下 FXG 文件来定义其方框和复选标记符号的外观:
  • CheckBox_down.fxg

  • CheckBox_downSymbol.fxg

  • CheckBox_downSymbolSelected.fxg

  • CheckBox_up.fxg

  • CheckBox_upSymbol.fxg

  • CheckBox_upSymbolSelected.fxg

如果在图形编辑器中打开这些文件,将显示如下内容:

复选框状态(down、downSymbol、downSymbolSelected、up、upSymbol 和 upSymbolSelected)

 

适用于多种分辨率的 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 文件后,将其应用到外观类。

要通过修改 FXG 文件来创建自定义外观,请执行以下操作:
  1. 创建自定义外观类并将其放在 customSkins 目录下,如创建移动设备外观类中所述。

  2. 在 customSkins 目录下创建一个子目录,例如 assets。创建子目录是可选步骤,但有助于组织 FXG 文件和外观类。

  3. 在 assets 目录下创建一个文件,并将现有 FXG 文件的内容复制到该文件中。例如,创建名为 CustomCheckBox_upSymbol.fxg 的文件。将 spark/skins/mobile160/assets/CheckBox_upSymbol.fxg 内容复制到新建的 CustomCheckBox_upSymbol.fxg 文件中。

  4. 更改新的 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>
  5. 在自定义外观类中,导入新 FXG 类,并将其应用到某个属性。例如,在 CustomCheckBox 类中:
    1. 导入新的 FXG 文件:
      //import spark.skins.mobile.assets.CheckBox_upSymbol; 
      import customSkins.assets.CustomCheckBox_upSymbol;
    2. 将新资源添加到自定义外观类中。例如,更改 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 文件。

下面的桌面示例呈示 CheckBox 组件的各种 FXG 资源(如果您在移动设备应用程序中使用该组件)。编译此示例时,将 frameworks\projects\mobiletheme\src\ 目录添加到编译器的 source-path 参数中。
<?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 才会滚动。只有在文本可以编辑或选择时,这些手势才会生效。

使文本可供编辑和选择

要使文本可以编辑或选择,请将 editable  selectable 属性设置为 true
textDisplay.editable = true; 
textDisplay.selectable = true;

双方向性

在 StyleableStageText 或 StyleableTextField 类中,文本不支持双方向性。

posted @ 2014-03-27 16:13  腐烂的翅膀  阅读(203)  评论(0编辑  收藏  举报