本文来源于 冰山上的播客 http://xinsync.xju.edu.cn , 原文地址:http://xinsync.xju.edu.cn/index.php/archives/1953
现在有许多关于如何为Flex程序加上皮肤的很好的资料。简单来说:Flex支持两种加载皮肤的方法:graphical和programmatic。graphical方法是在Flash,Photoshop,Fireworks等工具中创建图形资源,并把他们嵌入到你的Flex程序中。programmatic方法是创建一个为控件定义skin的ActionScript类。正如你猜测的那样,graphical方法比较简单,programmatic方法则比较强大。
这两种方法共同的一个缺点就是:为了能应用skin这些资源(graphical方法中的SWF/PNG/GIF/其他, programmatic方法中的AS类)都必须在编译时就是可用的。必须如此吗?在这篇文章中我将介绍一个巧妙的方法让graphical skins在运行时加载(通过一个带有源代码的示例)。
为了让这个例子尽量简单,我将创建一个允许Button控件动态加载皮肤的Flex程序。这个程序将在运行时连接到一个SWF,加载皮肤并且把它应用到Button控件。为了使它简单我将使用NJ文章中提供的皮肤模板文件,把RadioButton皮肤应用到Button控件。
第一步:为skin资源创建一个wrapper SWF
Skin资源在上述的skin模板文件中。我希望创建一个Flex程序可以在运行时加载并且可以从中提取适当资源的wrapper SWF,在这个例子中它就是RadioButton控件的四个symbol。下面是源码:
package
{
import flash.display.Sprite;
public class Wrapper extends Sprite
{
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_upIcon”)]
public var rbUpSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_downIcon”)]
public var rbDownSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_disabledIcon”)]
public var rbDisabledSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_overIcon”)]
public var rbOverSkin: Class;
}
}
第二步:把这个wrapper SWF放到你的服务器上
Flex程序需要从一个地方加载这个wrapper SWF!
第三步:在你的Flex程序中,使用Loader来加载这个wrapper SWF
我创建了一个叫做ClassLoader的有用的类来包装与加载SWF有关的功能并提取了这个类。下面是关键代码:
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
…
request = new URLRequest(swfLib);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
loader.load(request, context);
注意这个Loader把SWF加载到了一个ApplicationDomain中,当前的domain是它的parent。这是保证程序可以访问加载的类以及其中的资源的关键。
第四步:从加载的SWF中获得类并将它实例化。
这里我们使用一个一致的类名(这个例子中,是“Wrapper”)来加载类:
var wrapperClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class;
var wrapper:Object = new wrapperClass();
第五步:使用setStyle应用skins
你可以把skins应用到一个Button实例或者Button的所有实例。下面是方法:
StyleManager.getStyleDeclaration(”Button”).setStyle(”upSkin”, wrapper.rbUpSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”downSkin”, wrapper.rbDownSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”disabledSkin”, wrapper.rbDisabledSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”overSkin”, wrapper.rbOverSkin);
第六步:运行程序
我的例程(点击这里察看,可以“View Source”)展示了一个文本域,你可以向其中你输入wrapper SWF的URL(点击这里)。输入wrapper SWF的URL,点击Apply按钮,你会看到按钮现在看起来像一个特大型的单选按钮。当你将鼠标放在上面或者点击它的时候,你会发现它的外观会改变并显示适当的skin。如果你创建了自己的wrapper SWF并且其中包含了具有相同类名(rbUpSkin,等)的不同symbols,你可以把这个例程指向并加载它,从而显示不同的skins集合。
为什么你想要这样做呢?动态加载skin提供了一个难以置信的强大的功能:你可以让你的用户把他们的skin加载到你的程序中。想象一下一个用Flex创建的像Winamp一样的MP3播放器吧。开发者不需要为这个程序创建一个skin库,他只需要公布一个设置skin SWF(比如在参数对话框中)的UI并且让用户从一些团体创建的skin中任意选择。同样重要的是,开发者可以很精确地控制哪些控件可以加载skin那些需要保持原样(只在需要的控件上调用setStyle)。最后,把skins放在程序SWF外部将使得程序文件的大小不会因为skin文件的扩散而急速增加。
现在有许多关于如何为Flex程序加上皮肤的很好的资料。简单来说:Flex支持两种加载皮肤的方法:graphical和programmatic。graphical方法是在Flash,Photoshop,Fireworks等工具中创建图形资源,并把他们嵌入到你的Flex程序中。programmatic方法是创建一个为控件定义skin的ActionScript类。正如你猜测的那样,graphical方法比较简单,programmatic方法则比较强大。
这两种方法共同的一个缺点就是:为了能应用skin这些资源(graphical方法中的SWF/PNG/GIF/其他, programmatic方法中的AS类)都必须在编译时就是可用的。必须如此吗?在这篇文章中我将介绍一个巧妙的方法让graphical skins在运行时加载(通过一个带有源代码的示例)。
为了让这个例子尽量简单,我将创建一个允许Button控件动态加载皮肤的Flex程序。这个程序将在运行时连接到一个SWF,加载皮肤并且把它应用到Button控件。为了使它简单我将使用NJ文章中提供的皮肤模板文件,把RadioButton皮肤应用到Button控件。
第一步:为skin资源创建一个wrapper SWF
Skin资源在上述的skin模板文件中。我希望创建一个Flex程序可以在运行时加载并且可以从中提取适当资源的wrapper SWF,在这个例子中它就是RadioButton控件的四个symbol。下面是源码:
package
{
import flash.display.Sprite;
public class Wrapper extends Sprite
{
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_upIcon”)]
public var rbUpSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_downIcon”)]
public var rbDownSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_disabledIcon”)]
public var rbDisabledSkin: Class;
[Embed(source=”flex_skins.swf”,symbol=”RadioButton_overIcon”)]
public var rbOverSkin: Class;
}
}
第二步:把这个wrapper SWF放到你的服务器上
Flex程序需要从一个地方加载这个wrapper SWF!
第三步:在你的Flex程序中,使用Loader来加载这个wrapper SWF
我创建了一个叫做ClassLoader的有用的类来包装与加载SWF有关的功能并提取了这个类。下面是关键代码:
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
…
request = new URLRequest(swfLib);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
loader.load(request, context);
注意这个Loader把SWF加载到了一个ApplicationDomain中,当前的domain是它的parent。这是保证程序可以访问加载的类以及其中的资源的关键。
第四步:从加载的SWF中获得类并将它实例化。
这里我们使用一个一致的类名(这个例子中,是“Wrapper”)来加载类:
var wrapperClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class;
var wrapper:Object = new wrapperClass();
第五步:使用setStyle应用skins
你可以把skins应用到一个Button实例或者Button的所有实例。下面是方法:
StyleManager.getStyleDeclaration(”Button”).setStyle(”upSkin”, wrapper.rbUpSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”downSkin”, wrapper.rbDownSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”disabledSkin”, wrapper.rbDisabledSkin);
StyleManager.getStyleDeclaration(”Button”).setStyle(”overSkin”, wrapper.rbOverSkin);
第六步:运行程序
我的例程(点击这里察看,可以“View Source”)展示了一个文本域,你可以向其中你输入wrapper SWF的URL(点击这里)。输入wrapper SWF的URL,点击Apply按钮,你会看到按钮现在看起来像一个特大型的单选按钮。当你将鼠标放在上面或者点击它的时候,你会发现它的外观会改变并显示适当的skin。如果你创建了自己的wrapper SWF并且其中包含了具有相同类名(rbUpSkin,等)的不同symbols,你可以把这个例程指向并加载它,从而显示不同的skins集合。
为什么你想要这样做呢?动态加载skin提供了一个难以置信的强大的功能:你可以让你的用户把他们的skin加载到你的程序中。想象一下一个用Flex创建的像Winamp一样的MP3播放器吧。开发者不需要为这个程序创建一个skin库,他只需要公布一个设置skin SWF(比如在参数对话框中)的UI并且让用户从一些团体创建的skin中任意选择。同样重要的是,开发者可以很精确地控制哪些控件可以加载skin那些需要保持原样(只在需要的控件上调用setStyle)。最后,把skins放在程序SWF外部将使得程序文件的大小不会因为skin文件的扩散而急速增加。