Apache flex 自定义复合控件在添加回VGROUP后仅0.5-1秒内未正确呈现
我将离开MXML,并在ActionScript中构建了一个自定义组件控件 我已正确显示控件。问题是在我将其从显示列表中删除并使用.addElement(control)方法重新添加后出现的 下面是再次添加它的代码Apache flex 自定义复合控件在添加回VGROUP后仅0.5-1秒内未正确呈现,apache-flex,actionscript,adobe,custom-controls,Apache Flex,Actionscript,Adobe,Custom Controls,我将离开MXML,并在ActionScript中构建了一个自定义组件控件 我已正确显示控件。问题是在我将其从显示列表中删除并使用.addElement(control)方法重新添加后出现的 下面是再次添加它的代码 private function displayParameters(parameters:ArrayCollection):void{ for(var index:int = 0; index<parameters.length; index++){ if
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);
}
}
}
当我使用vgParameters.addElement(control)
重新添加控件时,comboBoxMultiSelect
未正确呈现。按钮\u btn multiple
内的plusIcon
起初未正确定位,但大约0.5-1秒后会迅速自我纠正
我很确定问题在于comboBoxMultiSelect,只是不确定如何强制图标保持在同一位置
这是非常恼人的,在我努力工作之后,有人知道我做错了什么吗
谢谢:)
更新------>这是报告控制代码
[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, this, true));
}
public function addSelfToValueObject(valueObject:Object):Object{
valueObject[AmfPHPArgumentName] = _selection;
return valueObject;
}
}
突出的一点是在
updateDisplayList()
的实现中。正如您所知,这是您的组件应该调整其子对象大小和位置的地方(和/或进行任何编程绘图)
但与其直接设置子对象的宽度/高度,不如使用Flex生命周期方法之一:setActualSize()
或setLayoutBoundsSize()
。对spark组件使用setLayoutBoundsSize()
设置Flex组件的宽度/高度时,该组件将使其自身失效,以便在下一个更新周期可以重新渲染。但是,由于您试图在updateDisplayList()
中呈现组件,因此应小心不要使此方法中的子对象无效
setActualSize()
和setLayoutBoundsSize()
方法设置Flex组件的宽度/高度,但不会使组件无效
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
_horizontalGroup.setLayoutBoundsSize(unscaledWidth, unscaledHeight);
// if you wanted to position objects, you would set their x/y coordinates
// here with the move() or setLayoutBoundsPosition() methods
}
注意,在createChildren()
中似乎也在调整某些子对象的大小。。。在这种情况下,基本Flex组件是什么并不清楚(ReportControl扩展了什么类
这样做可能会消除渲染问题。与直接设置宽度/高度属性相比,它肯定会执行更少的代码
[编辑]
这可能是与HGroup
的交互,这在这个组件中是不必要的。虽然我认为以这种方式制作组件很有趣,但它可能更乏味……这就是@RIAStar明智地指出另一种方法的原因
如果你想继续沿着这条路走下去,还有一些进一步的想法:
1) 看看您在createChildren()
中所做的大小调整-例如,HGroup
被指定了一个百分比宽度,但在updateDisplayList()
中,它被指定了一个固定宽度(这可能是一个误导,但我不会设置百分比宽度)
2) 您可以在删除组件后或重新添加组件之前欺骗组件进行自我验证。一种可能是浪费时间的恶作剧的预感
3) 从组件中删除“HGroup”。这有点不必要:布局要求非常简单,只需几行Actionscript即可完成。随着布局要求变得越来越复杂,您的里程数也会有所不同
在createChildren()
中,将组合框和按钮直接添加到ui组件中。然后在updateDisplayList()
中调整它们的大小和位置,如下所示:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
var padding:Number = 10;
var gap:Number = 0;
// make the ComboBox consume all of the width execpt for 20px and gap + padding
var availableWidth:Number = unscaledWidth - 20 - gap - (2*padding);
_drp.setLayoutBoundsSize(availableWidth, unscaledHeight); // combo box 100% width
_btnMultiple.setLayoutBoundsSize(20, unscaledHeight); // button is 20px wide
// now position them ...
// probably should not use 0, rather calculate a Y coordinate that centers them
// in the unscaledHeight
_drp.setLayoutBoundsPosition(padding, 0);
_btnMultiple.setLayoutBoundsPosition(unscaledWidth - padding - 20, 0);
}
我将试着给你一个例子,说明我们在上面的评论中讨论过的Spark蒙皮体系结构的含义。这不是对你问题的直接回答,但我想你可能会觉得有趣。为了简洁起见,我必须使它比您的组件简单一些,因为您似乎已经为您的问题剥离了一些代码,所以我无法确切地知道它应该做什么
这将是一个组件,您可以通过单击按钮在正常和扩展状态之间切换。首先,我们创建皮肤类。通常,您会先创建主机组件,但这样解释会更容易
<!-- 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>
好吧,这里还有很多事情要做
- 首先看一下
SkinState
元数据声明:当一个皮肤类被分配给组件时,编译器将检查该皮肤是否实现了所需的状态
- 然后,
SkinPart
声明:主机组件上的属性名称必须与skin类中标记的id完全匹配。当required
设置为true
时,编译器将检查这些组件是否确实存在于皮肤中。如果需要可选蒙皮零件,请将其设置为false
李>
- 请注意,
toggleButton
的类型是IEventDispatcher
:从主机组件的角度来看,所有toggleButton
必须做的事情都是分派单击事件。这意味着我们现在可以用
创建一个皮肤,整个过程将以同样的方式工作。看看这有多强大
- 由于skinpart属性不会立即分配,因此我们会覆盖
partAdded()
方法,该方法将在组件可用时执行。在大多数情况下,这是连接事件侦听器的地方
- 在
toggleExpanded()
方法中,我们切换布尔值,就像您问题中的组件一样,但是我们只会使皮肤状态无效。这将导致皮肤调用getCurrentSkinState()
方法,并将其状态更新为返回的任何值
瞧!您有一个工作组件,其行为被很好地分割成一个actionscript类,您不必担心布局的复杂性。
<!-- 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>
[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";
}
}
<c:ComboBoxMultiSelect skinClass="my.skins.ComboBoxMultiSelectSkin" />
@namespace c "my.components.*";
c|ComboBoxMultiSelect {
skinClass: ClassReference("my.skins.ComboBoxMultiSelectSkin")
}