我正确显示控件.我从显示列表中删除它并使用.addElement(control)方法再次将其添加回来之后出现问题.
private function displayParameters(parameters:ArrayCollection):void{ for(var index:int = 0; index<parameters.length; index++){ if(parameters[index] is ReportControl){ var control:ReportControl = parameters[index] as ReportControl; control.percentWidth = 100; vgParameters.addElement(control); } } }
ReportControl是comboBoxMultiSelect的基类,如下所示. ReportControl没有任何图形特殊的内容,它只是作为其具体实现(多态)的编程接口.
public class comboBoxMultiSelect extends ReportControl{ [Embed("../Assets/Icons/plus-16.png")] private var plusIcon:Class; [Embed("../Assets/Icons/minus-16.png")] private var minusIcon:Class; private var expanded:Boolean = false; private var buttonIconChanged:Boolean = false; private var _drp:ComboBox; private var _btnMultiple:Button; private var _horizontalGroup:HGroup; private var _multiSelector:ReportGridSelector; private var _multiSelection:Boolean = true; private var bMultiSelectionChanged:Boolean = false; public function ToggleExpanded():void{ expanded = !_expanded; buttonIconChanged = true; invalidateSize(); invalidateProperties(); invalidateDisplayList(); } public function comboBoxMultiSelect(){ super(); } override protected function createChildren():void{ super.createChildren(); if(!_horizontalGroup){ _horizontalGroup = new HGroup(); _horizontalGroup.gap = 0; _horizontalGroup.percentWidth = 100; _horizontalGroup.height = ReportControl.SIZE_DEFAULT_HEIGHT; addChild(_horizontalGroup); } if(!_drp){ _drp = new ComboBox(); _drp.text = GuiText; _drp.percentWidth = 100; _drp.height = ReportControl.SIZE_DEFAULT_HEIGHT; _horizontalGroup.addElement(_drp); } if(!_btnMultiple && _multiSelection){ _btnMultiple = new Button; _btnMultiple.setStyle("icon",plusIcon); _btnMultiple.width = 20; _btnMultiple.height = ReportControl.SIZE_DEFAULT_HEIGHT; _btnMultiple.visible = true; _btnMultiple.addEventListener(MouseEvent.CLICK,function(event:MouseEvent):void{ ToggleExpanded(); }); _horizontalGroup.addElement(_btnMultiple); } } override protected function commitProperties():void{ super.commitProperties(); if(buttonIconChanged){ if(_expanded==true){ _btnMultiple.setStyle("icon",minusIcon); } else{ _btnMultiple.setStyle("icon",plusIcon); } buttonIconChanged = false; } } override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void{ super.updateDisplayList(unscaledWidth,unscaledHeight); _horizontalGroup.width = unscaledWidth; _horizontalGroup.height = unscaledHeight; } override protected function measure():void{ super.measure(); measuredMinWidth = measuredWidth = ReportControl.SIZE_DEFAULT_WIDTH; //minimum size //default size if(_expanded==true) measuredMinHeight= measuredHeight = 200; else measuredMinHeight= measuredHeight = ReportControl.SIZE_DEFAULT_HEIGHT; } }
当我使用vgParameters.addElement(control)添加控件时,comboBoxMultiSelect无法正确呈现.按钮_btnMultiple内的plusIcon最初没有正确定位,但随后在0.5-1秒之后快速纠正.
我很确定问题出在comboBoxMultiSelect中,只是不确定如何强制图标保持在同一个地方.
在我辛勤工作之后,这是非常烦人的,任何人都有关于我做错了什么的想法?
谢谢 :)
更新—–>这是ReportControl代码
[Event (name= "controlChanged",type="Reporting.ReportControls.ReportControlEvent")] [Event (name= "controlIsNowValid",type="Reporting.ReportControls.ReportControlEvent")] public class ReportControl extends UIComponent { private var _guiText:String; private var _amfPHPArgumentName:String; private var _reportResult:ReportResult; private var _sequence:int; private var _reportId:int; private var _controlConfiguration:ReportParameterVO; private var _isValid:Boolean = false; internal var _selection:Object; /** * SIZE_DEFAULT_HEIGHT = 22 */ internal static const SIZE_DEFAULT_HEIGHT:int = 22; /** * SIZE_DEFAULT_WIDTH = 150 */ internal static const SIZE_DEFAULT_WIDTH:int = 150; public function get ControlConfiguration():ReportParameterVO{ return _controlConfiguration; } public function set ControlConfiguration(value:ReportParameterVO):void{ _controlConfiguration = value; _guiText = (value ? value.GuiText:""); _amfPHPArgumentName = (value ? value.AMFPHP_ArgumentName: ""); _sequence = (value ? value.Sequence : null); _reportId = (value ? value.ReportId : null); } public function get IsValid():Boolean{ return _isValid; } public function get ReportID():int{ return _reportId; } public function get Sequence():int{ return _sequence; } public function get ControlRepResult():ReportResult{ return _reportResult; } public function set ControlRepResult(value:ReportResult):void{ _reportResult = value; } internal function set Selection(value:Object):void{ _selection = value; } internal function get Selection():Object{ return _selection; } public function get ParameterSelection():Object{ return _selection; } public function get GuiText():String{ return _guiText; } public function get AmfPHPArgumentName():String{ return _amfPHPArgumentName; } public function ReportControl(){ //TODO: implement function super(); } public function dispatchControlChanged():void{ this.dispatchEvent(new ReportControlEvent(ReportControlEvent.CONTROL_CHANGED,this,true)); } public function dispatchControlIsNowValid():void{ this.dispatchEvent(new ReportControlEvent(ReportControlEvent.CONTROL_IS_NOW_VALID,true)); } public function addSelfToValueObject(valueObject:Object):Object{ valueObject[AmfPHPArgumentName] = _selection; return valueObject; } }
解决方法
这将是一个组件,通过单击按钮,您可以在正常状态和展开状态之间切换.首先,我们将创建皮肤类.通常,您首先要创建主机组件,但这样解释起来会更容易.
<!-- my.skins.ComboBoxMultiSelectSkin --> <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" height.normal="25" height.expanded="200"> <fx:Metadata> [HostComponent("my.components.ComboBoxMultiSelect")] </fx:Metadata> <s:states> <s:State name="normal" /> <s:State name="expanded" /> </s:states> <s:layout> <s:HorizontalLayout gap="0" /> </s:layout> <s:ComboBox id="comboBox" width="100%" /> <s:Button id="toggleButton" width="20" icon.normal="@Embed('../Assets/Icons/plus-16.png')" icon.expanded="@Embed('../Assets/Icons/minus-16.png')"/> </s:Skin>
因此,我们完全设置了组件的外观和布局方式.你觉得你的头痛消失了吗?我觉得这很优雅.我们有两个状态,组件的高度将调整为当前选择的状态,按钮的图标也是如此.切换状态的方式和时间是组件行为,并将在主机组件中定义.
现在让我们用普通的ActionScript创建该主机组件.为此,我们将扩展SkinnableComponent(请注意,如果扩展SkinnableComponent而不是UIComponent,它也可以扩展ReportControl).
[SkinState("normal")] [SkinState("expanded")] public class ComboBoxMultiSelect extends SkinnableComponent { [SkinPart(required="true")] public var toggleButton:IEventDispatcher; [SkinPart(required="true")] public var comboBox:ComboBox; private var expanded:Boolean; override protected function partAdded(partName:String,instance:Object):void { super.partAdded(partName,instance); switch (instance) { case toggleButton: toggleButton.addEventListener(MouseEvent.CLICK,handleToggleButtonClick); break; case comboBox: comboBox.addEventListener(IndexChangeEvent.CHANGE,handleComboSelection); break; } } private function handleToggleButtonClick(event:MouseEvent):void { toggleExpanded(); } private function handleComboSelection(event:IndexChangeEvent):void { //handle comboBox selection } protected function toggleExpanded():void { expanded = !expanded; invalidateSkinState(); } override protected function getCurrentSkinState():String { return expanded ? "expanded" : "normal"; } }
好吧,这里还有很多事情要做.
>首先查看SkinState元数据声明:当为组件分配外观类时,编译器将检查该外观是否已实现所需的状态.
>然后是SkinPart声明:主机组件上的属性名称必须与外观类中的标记的id完全匹配.根据需要设置为true,编译器将检查这些组件是否确实存在于皮肤中.如果需要可选外观部件,请将其设置为false.
>请注意,toggleButton的类型是IEventDispatcher:从主机组件的角度来看,所有toggleButton都必须这样做,就是调度CLICK事件.这意味着我们现在可以创建一个皮肤,其中< s:Image id =“toggleButton”source =“...”/>整个事情会继续以同样的方式运作.看看这有多强大?
>因为skinpart属性未立即分配,所以我们覆盖partAdded()方法,该方法将在组件可用时执行.在大多数情况下,这是您连接事件侦听器的地方.
>在toggleExpanded()方法中,我们像问题中的组件一样切换布尔值,但是我们只会使皮肤状态无效.这将导致外观调用getCurrentSkinState()方法并将其状态更新为返回的值.
Etvoilà!你有一个工作组件,行为很好地分成了actionscript类,你不必担心布局错综复杂.如果您希望创建具有相同行为的组件,但它应该水平扩展而不是垂直扩展:只需创建一个调整宽度而不是高度的新外观,并将其分配给同一主机组件.
等一下!我差点忘了告诉你如何将皮肤分配给组件.你可以内联:
<c:ComboBoxMultiSelect skinClass="my.skins.ComboBoxMultiSelectSkin" />
或通过造型:
@namespace c "my.components.*"; c|ComboBoxMultiSelect { skinClass: ClassReference("my.skins.ComboBoxMultiSelectSkin") }