Flex4与之前版本的一个极大区别就是外观皮肤的分离,虽然进一步解耦,但存在一个不爽的地方就是增加了编码的工作量,你能想象为你的每个自定义组件都写一个对应的皮肤吗?可能仅仅和你之前写过的组件差了那么一点点而已,可是工作量double,更进一步使代码的管理复杂化。
下面是我自己写的一个通用的自定义ImageButton,有呆毛(Demo)才有真相:
1.首先创建一个Skinnable组件,继承自Button(一个很大的好处就是支持defaultButton,普通的组件是不支持的,这是促成我写这个组件的原始动力),类名就定义为ImageButton:
package cn.shawnlee.components { import spark.components.Button; public class ImageButton extends Button { public function ImageButton() { super(); } } }
2.好了,组件已经建立了,然后先建立一个皮肤,再来考虑逻辑,新建MXML外观,定义为ImageButtonSkin,主机组件定位到刚才建立的ImageButton:
<?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("cn.shawnlee.components.ImageButton")] </fx:Metadata> <!-- states --> <s:states> <s:State name="disabled" /> <s:State name="down" /> <s:State name="over" /> <s:State name="up" /> </s:states> <!-- SkinParts name=iconDisplay, type=spark.primitives.BitmapImage, required=false name=labelDisplay, type=spark.core.IDisplayText, required=false --> </s:Skin>
3.现在来考虑显示逻辑,我们仅仅需要用图片来代替按钮的默认外观,但考虑到按钮的四种状态,我需要用四个BitmapImage来分别装载四个图片,用来在不同状态下显示,因此,在外观中直接加入
<s:BitmapImage id="imageDisabledDisplay" includeIn="disabled" /> <s:BitmapImage id="imageDownDisplay" includeIn="down" /> <s:BitmapImage id="imageOverDisplay" includeIn="over" /> <s:BitmapImage id="imageUpDisplay" includeIn="up" />
4.由此外观皮肤已经做好了,对,就这么简单,下面只需要在显示逻辑上做文章就可以了,来看看ImageButton类,我们需要把外观中加入的四个BitmapImage在类中进行定义声明,以便可以在代码中进行调用和控制:
[SkinPart(require="false")] public var imageDisabledDisplay:BitmapImage; [SkinPart(require="false")] public var imageDownDisplay:BitmapImage; [SkinPart(require="false")] public var imageOverDisplay:BitmapImage; [SkinPart(require="false")] public var imageUpDisplay:BitmapImage;
5.接下来考虑显示逻辑,我希望我的组件能够很方便的这么使用:
<cn:ImageButton image="@Embed('./btn.png')" imageDown="@Embed('./btnDown.png')" imageOver="@Embed('./btnOver.png')" />
如果我比较懒,我只是需要一张图片,那么就只定义image,如果我还想详细的定义up,down,over,disabled状态下的图片,则通过imageUp,imageDown,imageOver,imageDisabled来定义,所以我的组件需要自定义五个Style样式:
[Style(name="image", type="Class", format="EmbeddedFile", inherit="no")] [Style(name="imageDisabled", type="Class", format="EmbeddedFile", inherit="no")] [Style(name="imageDown", type="Class", format="EmbeddedFile", inherit="no")] [Style(name="imageOver", type="Class", format="EmbeddedFile", inherit="no")] [Style(name="imageUp", type="Class", format="EmbeddedFile", inherit="no")] public class ImageButton extends Button
6.好了,image样式表示默认的图片,如果没有设置对应状态下的图片,则以image样式的图片显示,为此,我需要自定义一个私有方法,来返回各个状态下应该显示出的图片:
private function getImageStyle(styleProp:String):* { var value:* = getStyle(styleProp); return value==null?getStyle("image"):value; }
7.然后就是自定义组件不可缺少的一步,重写partAdded方法:
override protected function partAdded(partName:String, instance:Object):void { super.partAdded(partName, instance); if(instance == imageDisabledDisplay) { imageDisabledDisplay.source = getImageStyle("imageDisabled"); } if(instance == imageDownDisplay) { imageDownDisplay.source = getImageStyle("imageDown"); } if(instance == imageOverDisplay) { imageOverDisplay.source = getImageStyle("imageOver"); } if(instance == imageUpDisplay) { imageUpDisplay.source = getImageStyle("imageUp"); } }
上面的过程使ImageButton在添加各个BitmapImage子组件时根据对应的Style样式设置各自的图片source属性,至此,组件完成,是不是很简单?
【源代码下载】