分组框(Group Box)是围绕在一组相关控件周围的带标签的矩形边框。它提供了一种通过视觉展示控件关系
的方法。如下图所示:
本文将通过以下几步来实现:
一、继承SkinnableContainer,创建组件类GroupBox。
二、声明外观部件titleDisplay用来显示组合框的标题。
三、增加title属性。
四、覆盖partAdded方法,使标题字符串能够作用于外观部件titleDisplay。
五、创建它的默认外观(皮肤)GroupBoxSkin。
六、为GroupBox增加必要样式。
---------------
一、继承SkinnableContainer,创建组件类GroupBox。
public class GroupBox extends SkinnableContainer { public function GroupBox() { super(); } }
二、声明外观部件titleDisplay用来显示组合框的标题。
[SkinPart(required="false")] public var titleDisplay:TextBase;
三、增加title属性。
private var _title:String = ""; [Bindable] public function get title():String { return _title; } public function set title(value:String):void { _title = value; if (titleDisplay) titleDisplay.text = title; }
四、覆盖partAdded方法,使标题字符串能够作用于外观部件titleDisplay。
override protected function partAdded(partName:String, instance:Object):void { super.partAdded(partName, instance); if (instance == titleDisplay) { titleDisplay.text = title; } }
至此,GroupBox组件类基本创建完成,但是还不能显示。下面来创建它的默认外观(皮肤)GroupBoxSkin。
五、创建它的默认外观(皮肤)GroupBoxSkin。
第一步,创建组合框的边框。
<!-- 边框 --> <s:Rect id="border" left="0" right="0" top="10" bottom="0" radiusX="4" radiusY="4" > <s:stroke> <s:SolidColorStroke id="borderStroke" weight="1"/> </s:stroke> </s:Rect>
第二步,创建外观部件titleDisplay。
<!-- 标题 --> <s:Label id="titleDisplay" maxDisplayedLines="1" left="9" top="0" minHeight="20" verticalAlign="middle" textAlign="start"/>
第三步,创建外观部件contentGroup,用于包含组合框的内容。
<!-- 内容区域 --> <s:Group id="contentGroup" left="5" right="5" top="21" bottom="5"> <s:layout> <s:VerticalLayout/> </s:layout> </s:Group>
注意,此时边框是一个闭合的矩形。
图2
从上图,可以看出现在组合框的标题文字与边框是重叠的,显然这不符合我们的要求。
为了解决这个问题,下面要为边框创建一个遮罩。
<!-- 边框遮罩 --> <s:Group id="borderGroupMask" left="0" right="0" top="0" bottom="0"> <s:Rect left="0" width="7" top="0" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> <s:Rect left="7" width="{titleDisplay.width+4}" top="30" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> <s:Rect left="{titleDisplay.width+11}" width="100%" top="0" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> </s:Group>
为<s:Rect id="border"/>增加属性:mask="{borderGroupMask}"。
六、为GroupBox增加必要样式。
第一步,在GroupBox类中增加以下样式声明,它们用来指定边框的颜色和圆角。
增加borderColor样式。
[Style(name="borderColor", type="uint", format="Color", inherit="no", theme="spark")] [Style(name="cornerRadius", type="Number", format="Length", inherit="no", theme="spark")]
第二步,在GroupBoxSkin中覆盖updateDisplayList,把样式应用于外观。
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { var cr:Number = getStyle("cornerRadius"); if (cornerRadius != cr) { cornerRadius = cr; // 取变量 border.topLeftRadiusX = cornerRadius; border.topRightRadiusX = cornerRadius; border.bottomLeftRadiusX = cornerRadius; border.bottomRightRadiusX = cornerRadius; } borderStroke.color = getStyle("borderColor"); borderStroke.alpha = getStyle("borderAlpha"); // super.updateDisplayList(unscaledWidth, unscaledHeight); }
至此所有工作完成。效果如下:
图3
完整的文件如下:
1 GroupBox.as
package jx.components { import spark.components.SkinnableContainer; import spark.components.supportClasses.TextBase; /** * The alpha of the border for this component. * * @default 0.5 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="borderAlpha", type="Number", inherit="no", theme="spark")] /** * The color of the border for this component. * * @default 0 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="borderColor", type="uint", format="Color", inherit="no", theme="spark")] /** * The radius of the corners for this component. * * @default 5 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="cornerRadius", type="Number", format="Length", inherit="no", theme="spark")] public class GroupBox extends SkinnableContainer { public function GroupBox() { super(); } //---------------------------------- // titleField //---------------------------------- [SkinPart(required="false")] /** * 定义容器中标题文本的外观的外观部件。 * * @see jx.skins.GroupBoxSkin * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var titleDisplay:TextBase; //---------------------------------- // title //---------------------------------- /** * @private */ private var _title:String = ""; /** * @private */ private var titleChanged:Boolean; [Bindable] /** * 标题或者说明。 * @default "" * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get title():String { return _title; } /** * @private */ public function set title(value:String):void { _title = value; if (titleDisplay) titleDisplay.text = title; } override protected function partAdded(partName:String, instance:Object):void { super.partAdded(partName, instance); if (instance == titleDisplay) { titleDisplay.text = title; } } } }
2 GroupBoxSkin.mxml
<?xml version="1.0" encoding="utf-8"?> <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5"> <fx:Metadata> [HostComponent("jx.components.GroupBox")] </fx:Metadata> <fx:Script fb:purpose="styling"> static private const exclusions:Array = ["titleDisplay", "contentGroup"]; /** * @private */ override public function get colorizeExclusions():Array { return exclusions; } /** * @private */ override protected function initializationComplete():void { useChromeColor = true; super.initializationComplete(); } private var cornerRadius:Number; /** * @private */ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { var cr:Number = getStyle("cornerRadius"); if (cornerRadius != cr) { cornerRadius = cr; // 取变量 border.topLeftRadiusX = cornerRadius; border.topRightRadiusX = cornerRadius; border.bottomLeftRadiusX = cornerRadius; border.bottomRightRadiusX = cornerRadius; } borderStroke.color = getStyle("borderColor"); borderStroke.alpha = getStyle("borderAlpha"); // super.updateDisplayList(unscaledWidth, unscaledHeight); } </fx:Script> <s:states> <s:State name="normal" /> <s:State name="disabled" /> </s:states> <!-- 边框遮罩 --> <s:Group id="borderGroupMask" left="0" right="0" top="0" bottom="0"> <s:Rect left="0" width="7" top="0" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> <s:Rect left="7" width="{titleDisplay.width+4}" top="30" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> <s:Rect left="{titleDisplay.width+11}" width="100%" top="0" bottom="0"> <s:fill> <s:SolidColor color="#ff0000" alpha="1"/> </s:fill> </s:Rect> </s:Group> <!-- 边框 --> <s:Rect id="border" left="0" right="0" top="10" bottom="0" radiusX="4" radiusY="4" mask="{borderGroupMask}" ><!--mask="{borderGroupMask}"--> <s:stroke> <s:SolidColorStroke id="borderStroke" weight="1"/> </s:stroke> </s:Rect> <!-- 标题 --> <s:Label id="titleDisplay" maxDisplayedLines="1" left="9" top="0" minHeight="20" verticalAlign="middle" textAlign="start"/> <!-- 内容区域 --> <s:Group id="contentGroup" left="5" right="5" top="21" bottom="5"> <s:layout> <s:VerticalLayout/> </s:layout> </s:Group> </s:SparkSkin>
3 GroupBoxExam.mxml 实例文件
<?xml version="1.0" encoding="utf-8"?> <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" minWidth="955" minHeight="600" xmlns:components="jx.components.*"> <s:layout> <s:BasicLayout/> </s:layout> <fx:Declarations> </fx:Declarations> <components:GroupBox skinClass="jx.skins.GroupBoxSkin" title="用户配置文件" cornerRadius="5"> <components:layout> <s:HorizontalLayout/> </components:layout> <s:Button/> <s:Button/> <s:Button/> </components:GroupBox> </s:Application>
4 css
可以通过css为GroupBox指定样式的默认值。
@namespace components "jx.components.*"; components|GroupBox { skinClass: ClassReference("jx.skins.GroupBoxSkin"); cornerRadius: 5; borderColor: #104778; borderWeight: 1; dropShadowVisible: false; }
5 代码方式指定组件的默认CSS样式
private static const classConstructed:Boolean = classConstruct(); // 指定默认样式 private static function classConstruct():Boolean { var styleManager:IStyleManager2 = FlexGlobals.topLevelApplication.styleManager; if (!styleManager.getStyleDeclaration("jx.components.GroupBox")) { var css:CSSStyleDeclaration = new CSSStyleDeclaration(null, styleManager); css.defaultFactory = function():void { this.skinClass = GroupBoxSkin; this.borderAlpha = 1; this.borderColor = 0; // 黑 // this.borderColor = 0xD3D3D3; // 灰 // this.borderColor = 0x104778; // 蓝 this.cornerRadius = 5; // this.dropShadowVisible = true; // this.borderWeight = 1; } styleManager.setStyleDeclaration("jx.components.GroupBox", css, true); } return true; }
完整的项目请下载附件GroupBoxExam.zip。