您的位置:首页 > 其它

Flex移动皮肤-第一部分:增强的皮肤功能基础

2012-04-18 13:21 411 查看
Flex 4.5提供的移动增强的皮肤特性,支持触摸交互、性能优良,并且考虑到了内存占用问题。尽管目前市场上有不少性能优异的设备,但典型的Spark皮肤(包括Flex 4引入的默认皮肤)却没有能够在移动设备上得到很好的应用。Adobe为移动优化过的皮肤在设计时就考虑到平衡两个对立的目标:性能优异却又容易创建。虽然MXML皮肤在某些情况下是有用的,但Adobe还是建议遵循以下简单的方针,确保Flex 4.5移动应用程序能够同时满足开发者和最终用户的性能要求。

这是介绍Flex 4.5移动皮肤特性系列文章中的第一篇。

本文将涵盖创建移动增强皮肤的基本知识,包括:

Spark主题和Mobile主题的区别

MobileSkin基类中包含的性能优化

用FXG替代MXML图形

基于Mobile主题的ButtonSkin类创建自定义的Button皮肤

该系列文章中的余下几篇将会介绍更多高级主题,包括:

基于MobileSkin基类构建新的皮肤

创建空间感知的皮肤,可以适应所有屏幕尺寸

使用CSS媒体查询为每个平台创建自定义的主题


比较Spark和Mobile 主题

Mobile主题基本是Flex 4引入的Spark主题功能集的一个子集。Mobile主题专门针对性能和内存占用问题进行的优化。


MobileSkin 基类

Spark 皮肤通常需要继承 Skin (它扩展了 Group) 或者 SparkSkin (它扩展了 Skin)。Mobile主题里的皮肤使用一个新的基类MobileSkin,它扩展了UIComponent。


状态

MobileSkin对状态的支持是它一项针对移动开发优化过的主要特性。一般情况下,使用状态特性(在MXML或者ActionScript)都会带来额外的内存和性能消耗。而MobileSkin不再用State类及子类,而是手工的在代码里处理状态改变,例如
SetProperty
AddChild


布局

因为MobileSkin不是一个 Group, 它不能使用 Spark的基于约束的布局。例如 HorizontalLayout, VerticalLayout和BasicLayout 。

MobileSkin的内容在代码中人工的布局。MobileSkin加入了新的生命周期方法
layoutContents(),
,它在
updateDisplayList()
中被调用。这个方法用于放置皮肤的子元素。


FXG 和 MXML 图形

Mobile主题中皮肤的图形由编译过的FXG和用于绘制的ActionScript代码构成。绘制代码仅用于琐碎的图形或者需要支持样式的时候。处于性能优化的考虑,所有其他图形都使用编译过的FXG。MobileSkin基类不选择使用MXML图形,除非他们都包含在一个Group当中。


文本

Mobile主题在默认皮肤中不会使用Flash Text Engine (FTE)或者Text Layout Framework (TLF) 。这主要是基于性能的考虑,并且为了支持原生的文本输入和编辑。

Flex 4.5在mobilecomponents.swc中引入了一个新的StyleableTextField类。它扩展了TextField,并且加入了对样式的支持。它专门用于那些不准备与MXML结合使用的移动ActionScript皮肤和渲染器。

在同时使用StyleableTextField 和 Label (基于 FTE)时,开发者必须嵌入字体两次。Label 使用
embedAsCFF=true
,而
TextField 和 StyleableTextField 用
embedAsCFF=false


Adobe不建议在移动项目中使用RichEditableText组件。请用TextArea组件代替。


MXML 和 ActionScript

由于MobileSkin删除了MXML皮肤的需要主要的申明性特性(状态、布局和MXML图形),Adobe建议用ActionScript编写皮肤。没有这三个特性,用MXML做声明性的标识已经没有什么优势了。

注意: 在Flash Builder中,可以指定库和主题的SWCs的代码或者编译过的ActionScript皮肤,由设计视同渲染出MXML皮肤。但设计视图不能通过指定代码渲染ActionScript皮肤。


不支持的全局样式

由于上文提到限制,Mobile主题删除了一些样式,包括:

rollOverColor

不支持,因为基础可触屏的界面是目前主要环境。

borderAlpha
,
borderColor
,
cornerRadius

不支持,因为这些参数是编译过的FXG的属性,他们不会在运行时发生变化

dropShadowVisible

不支持,为性能考虑,尽量减少过滤器的使用。

Flash Builder 会根据当前选择的主题,在MXML和CSS编辑器中正确的显示或者隐藏样式属性


Mobile中避免使用的组件

由于各种原因,某些Spark组件在Mobile主题中没有皮肤。例如,有些组件在Mobile UI下没有什么作用,或者它根本就不是 Flex 4.5 版本的主要目标,可能在下一个发行版中专门为移动平台进行优化。这些组件包括:

ComboBox and DropDownList

NumericStepper

ToggleButton

VideoDisplay and VideoPlayer

VSlider

Panel

TabBar (the component used in TabbedViewNavigator is actually a ButtonBar)

TitleWindow


Button皮肤教程概述

开始使用皮肤特性的最佳方式是,基于默认的Buton皮肤,创建一个自定义的Button皮肤。为了让问题简单化,这个例子没有考虑到屏幕DPI的问题。笔者将在系列文章的其他篇幅讨论这些问题。

首先,使用 Adobe Illustrator CS5为Button图形创建一个FXG文件。这个文件将同时展现Button组件的
up
down
皮肤状态。因为这里主要针对触摸输入,所以没有创建
over
状态。

其次,通过重载MobileSkin的
drawBackground()
方法,添加对
chromeColor
样式的支持。或者,也可以手动在up和down的图形里添加固定的背景颜色,然后重载
drawBackground()
方法,不作任何事情。
disabled
状态仅仅会改变
up
状态的
alpha
值。移动ButtonSkin类已经默认包含这个功能。


教程第一步:创建FXG图形

根据自己的喜好,可以选择Adobe Flash Professional、Adobe Illustrator或者 Adobe Fireworks构建FXG。你也可以在Flash Builder中手工编辑FXG,然后在MXML文件中移动这个FXG,再用设计视图渲染它,可视化的检查结果。


用 Illustrator 创建 FXG

这个例子用 Illustrator 创建一个药丸形状的Button图形.

在Illustrator中,选择 File > New。

为图形命名,例如RoundedButtonExport

设置 New Document Profile 为Flash Catalyst。

设置大小为典型的手机尺寸 480 px x 800 px 。

点击 OK

用矩形工具新建一个由灰色笔触,渐变填充的矩形。

在Stroke面板中,找到Align Stroke,选择中间的Align Stroke To Inside选项。默认情况下,笔触都是居中对齐的。笔者将稍候介绍为什么最好避免使用这个默认值。

修改 X 和 Y 位置为 0.

选中矩形后,选择 Effect > Stylize > Round Corners。

指定角的半径为 22 px。

保存为没有私有数据的 FXG 。


清理 FXG

导出FXG文件后,你可能希望清理一些不需要的标签,例如多余的Group标签或者私有的命名空间数据。这个步骤不是必须的,不过这样做可以让你的FXG更容易让人理解。

RoundedButtonExport.fxg

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" viewHeight="800" viewWidth="480" ai:appVersion="15.0.2.399" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="800" d:pageWidth="480" d:type="layer" d:userLabel="Artboard 1">
<Group ai:seqID="2" d:type="layer" d:userLabel="Layer 1">
<Group ai:seqID="3" flm:knockout="false" d:type="layer" d:userLabel="RoundedButton">
<Group ai:seqID="4" flm:knockout="false">
<Path x="0.5" y="1" winding="nonZero" ai:seqID="5" data="M21.5 43C9.64502 43 0 33.355 0 21.5 0 9.64502 9.64502 0 21.5 0L197.5 0C209.355 0 219 9.64502 219 21.5 219 33.355 209.355 43 197.5 43L21.5 43Z">
<fill>
<LinearGradient x="109.5" y="0" scaleX="43" rotation="90">
<GradientEntry ratio="0" color="#F0F0F0"/>
<GradientEntry ratio="0.478788" color="#C8C8C8"/>
<GradientEntry ratio="0.50303" color="#BBBBBB"/>
<GradientEntry ratio="1" color="#F0F0F0"/>
</LinearGradient>
</fill>
</Path>
<Path winding="nonZero" ai:seqID="6" data="M198 1C209.58 1 219 10.4204 219 22 219 33.5796 209.58 43 198 43L22 43C10.4204 43 1 33.5796 1 22 1 10.4204 10.4204 1 22 1L198 1M198 0 22 0C9.8999 0 0 9.8999 0 22 0 34.1001 9.8999 44 22 44L198 44C210.1 44 220 34.1001 220 22 220 9.8999 210.1 0 198
0L198 0Z">
<fill>
<SolidColor color="#DDDDDD"/>
</fill>
</Path>
</Group>
</Group>
</Group>
</Group>
<Private/>
</Graphic>


RoundedButtonCleanup.fxg

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" xmlns="http://ns.adobe.com/fxg/2008">
<Path x="0.5" y="1" winding="nonZero" data="M21.5 43C9.64502 43 0 33.355 0 21.5 0 9.64502 9.64502 0 21.5 0L197.5 0C209.355 0 219 9.64502 219 21.5 219 33.355 209.355 43 197.5 43L21.5 43Z">
<fill>
<LinearGradient x="109.5" y="0" scaleX="43" rotation="90">
<GradientEntry ratio="0" color="#F0F0F0"/>
<GradientEntry ratio="0.478788" color="#C8C8C8"/>
<GradientEntry ratio="0.50303" color="#BBBBBB"/>
<GradientEntry ratio="1" color="#F0F0F0"/>
</LinearGradient>
</fill>
</Path>
<Path winding="nonZero" data="M198 1C209.58 1 219 10.4204 219 22 219 33.5796 209.58 43 198 43L22 43C10.4204 43 1 33.5796 1 22 1 10.4204 10.4204 1 22 1L198 1M198 0 22 0C9.8999 0 0 9.8999 0 22 0 34.1001 9.8999 44 22 44L198 44C210.1 44 220 34.1001 220 22 220 9.8999 210.1 0 198
0L198 0Z">
<fill>
<SolidColor color="#DDDDDD"/>
</fill>
</Path>
</Graphic>


测试 FXG

导出和清理 FXG之后,你可以把它丢进一个MXML文件中,用设计视图预览,从而快速的验证它是否工作。

尝试以下步骤:

在Flash Builder中新建一个项目(可以命名为任何名字)。

在源代码文件夹中加入 FXG 文件。

切换到设计视图

组件面板将会把FXG文件显示为一个自定义组件。

拖拽这个组件到设计区域。你可以看到FXG被渲染成原本的大小。

在设计视图中,尝试改变FXG的宽度。

你将发现圆角在水平方向拉伸(见图1)。但你希望看到的应该是圆角的形状保持不变,而是让图形的中间部分拉伸。为此,需要为FXG加入伸缩网格信息。



图 1.缺少伸缩网格数据


手工添加scale grids

为让grid伸缩适当的伸缩,你需要添加网格的左、右、上和下的位置信息。因为使用了Round Corners风格化选项,我们知道当前的半径是22px。有了这些信息,你可以打开Flash Builder,对FXG文件做如下修改:

<Graphic>
根标签中添加
scaleGridLeft="22"
scaleGridRight="198px"
(图形的完整宽度是
220px)

你还需要确保边界的笔锋没有伸缩。

在同一个标签中,为这个图形添加
scaleGridTop="1px"
scaleGridBottom="43px"
(图形的完整高度是
44px)

注意: 对于有些图形,很难找到任意路径上的精确起始点。这种情况下,请使用Illustrator的选择工具去覆盖一个锚点,从而找到它的坐标(见图2)。



图 2.找到锚点坐标

在Graphic根标签添加网格数据之后,查看一下设计视图中的新FXG,你会发现没有什么变化。因为路径信息并没有填满图形的全部尺寸,所以伸缩网格没有变化。

为了修复这个问题,如下所示,添加一个透明的Rect占据整个图形空间。

将刚做的修改保存为RoundedButton.fxg.

RoundedButton.fxg

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" xmlns="http://ns.adobe.com/fxg/2008" scaleGridLeft="22" scaleGridRight="198" scaleGridTop=”1” scaleGridBottom=”43”>
<Path x="0.5" y="1" winding="nonZero" data="M21.5 43C9.64502 43 0 33.355 0 21.5 0 9.64502 9.64502 0 21.5 0L197.5 0C209.355 0 219 9.64502 219 21.5 219 33.355 209.355 43 197.5 43L21.5 43Z">
<fill>
<LinearGradient x="109.5" y="0" scaleX="43" rotation="90">
<GradientEntry ratio="0" color="#F0F0F0"/>
<GradientEntry ratio="0.478788" color="#C8C8C8"/>
<GradientEntry ratio="0.50303" color="#BBBBBB"/>
<GradientEntry ratio="1" color="#F0F0F0"/>
</LinearGradient>
</fill>
</Path>
<Path winding="nonZero" data="M198 1C209.58 1 219 10.4204 219 22 219 33.5796 209.58 43 198 43L22 43C10.4204 43 1 33.5796 1 22 1 10.4204 10.4204 1 22 1L198 1M198 0 22 0C9.8999 0 0 9.8999 0 22 0

34.1001 9.8999 44 22 44L198 44C210.1 44 220 34.1001 220 22 220 9.8999 210.1 0 198
0L198 0Z">
<fill>
<SolidColor color="#DDDDDD"/>
</fill>
</Path>
<!-- scale grid fix -->
<Rect x="0" y="0" width="220" height="44">
<fill>
<SolidColor color="#000000" alpha="0"/>
</fill>
</Rect>
</Graphic>


现在,设计视图中的Button应该伸缩自如了。(见图 3)



图 3.添加了伸缩网格后的组件。


教程步骤2: 创建皮肤类

基于现有的Mobile主题,创建一个新的Button皮肤的过程氛围3个主要步骤。

新建一个spark.skins.mobile.ButtonSkin的子类。

在构造函数中,设置FXG类的
upBorderSkin
downBorderSkin
属性。注意,这些是类实行,而不是FXG的实例。同样,为FXG的尺寸信息设置
measuredDefaultHeight
measuredDefaultWidth
属性(参考下面的代码片段)。

用CSS或者XML设置Button的
skinClass
属性。

注意: 这个项目的示例文件中包含RoundedButtonSkinProject.fxp。您可以将这个文件导入Flash Builder,查看完整的应用程序(包括皮肤在内)是如何实现的。

关于
chromeColor
样式,你有3个选择:

不支持
chromeColor

重载
drawBackground()
,不作任何事情

绘制
chromeColor
,使其符合FXG图形
– 重载
drawBackground()
,用代码绘制
chromeColor
。并且为FXG添加alpha值,使得
chromeColor
可见。

chromeColor
填色
- 重载
drawBackground()
,用工具方法
applyColorTransform()
将FXG从基色转变为特定的
chromeColor


这个例子演示了第三种方法。

下面的代码是皮肤的最终实现。

RoundedButtonSkin.as

package skins
{
import skins.assets.RoundedButton;

import spark.skins.mobile.ButtonSkin;

public class RoundedButtonSkin extends ButtonSkin
{
private var colorized:Boolean = false;

public function RoundedButtonSkin()
{
super();

// replace FXG asset classes
upBorderSkin = skins.assets.RoundedButton;
downBorderSkin = skins.assets.RoundedButton;

measuredDefaultHeight = 44;
measuredDefaultWidth = 220;
}

override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
{
// omit call to super.drawBackground() to apply tint instead and don't draw fill
var chromeColor:uint = getStyle("chromeColor");

if (colorized || (chromeColor != 0xDDDDDD))
{
// apply tint instead of fill
applyColorTransform(border, 0xDDDDDD, chromeColor);

// if we restore to original color, unset colorized
colorized = (chromeColor != 0xDDDDDD);
}
}
}
}


教程步骤3: 测试

下面的代码将定制过的RoundedButtonSkin设置为Button的默认皮肤。为了演示
chromeColor
和CSS,作者在此为Buttondown状态加入了一些样式。

<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
s|Button
{
skinClass: ClassReference("skins.RoundedButtonSkin");
}

s|Button:down
{
chromeColor: #0000FF;
color: #FFFFFF;
textShadowColor: #000000;
}
</fx:Style>


在应用程序中添加一些Button后,你应该能看到他们的新皮肤在弹起和按下时的不同状态(见图4)。down状态时的皮肤表明CSS样式已经起作用了。



图 4.拥有新皮肤的Button。


FXG 提示与技巧

在处理FXG时,请记住下列注意事项。


路径 vs 原始图形

路径信息并不总是很容易找到,但有些情况下,路径还可能与一些反锯齿的元素渲染在一起。你每次需要获得的路径信息总是不同的。当你在Illustrator中难以获取路径信息时,不要立刻就期望简化原始图形。


blendMode

图形元素的
blendMode
属性默认是设置为
自动的
。当它是
auto
时候,Flash
Player或者AIR运行时将会正确的判断出元素本身是否需要根据
alpha
值使用
blendMode
层。


尽可能避免笔触

通常情况下,笔触会横跨图形的边缘(例如,在Illustrator中使用"笔触居中对其")

举例来说,画一条从(0,0)到(0,100)的一条线,它有1个像素宽的笔触。该笔触将会从X轴的-.5延展到.5。但是由于在小数位的像素空间内无法绘制任何东西,Flash将会画一条反锯齿的2个像素宽的线,正好占据该小数宽度位置。为了消除反锯齿的干扰,画图形的时候使用奇数做为笔触大小,使得它能有半个像素的边界。例如,一个占据(10,10)位置的、
1
个像素宽的
SolidColorStroke
笔触,应该实际占位在(10.5,10.5)。

尽可能使用填充矩形,而非有笔触的矩形和线条。如果必须使用有笔触的
填充
矩形
,那可以尝试把它分位两个填充矩形(假设填充万全不透明)。如果要画一个条线,尝试把它转变为一个填充矩形。例如,如果要画一条水平直线,可以创建一个高度等同于线条笔触的填充矩形。


伸缩网格

在用FXG设计图形时,必须考虑到伸缩网格的一些局限。

伸缩网格的值必须在图形的边界之内,并且不能与特性边界重合(也就是说,左边界
scaleGridLeft
<
scaleGridRight
<
右边界)。

如果图形包含Group元素,就不能用伸缩网格。

如果元素使用了
alpha
属性,伸缩网格也不能使用。所以,只在笔触和
填充
元素上应用
alpha


FXG规范

FXG的完整规范,请参考《FXG 2.0 - 功能与设计规范》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: