flex – 自定义复合控件在添加回VGROUP后仅在0.5-1秒内无法正确渲染

我正在远离MXML并在ActionScript中构建了一个自定义组件控件.

我正确显示控件.我从显示列表中删除它并使用.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;
    }

}

解决方法

我将尝试举例说明我们在上面的评论中讨论过的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>

因此,我们完全设置了组件的外观和布局方式.你觉得你的头痛消失了吗?我觉得这很优雅.我们有两个状态,组件的高度将调整为当前选择的状态,按钮的图标也是如此.切换状态的方式和时间是组件行为,并将在主机组件中定义.

现在让我们用普通的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")
}

相关文章

一:display:flex布局display:flex是一种布局方式。它即可以...
1. flex设置元素垂直居中对齐在之前的一篇文章中记载过如何...
移动端开发知识点pc端软件和移动端apppc端软件是什么,有哪些...
最近挺忙的,准备考试,还有其他的事,没时间研究东西,快周...
display:flex;把容器设置为弹性盒模型(设置为弹性盒模型之后...
我在网页上运行了一个Flex应用程序,我想使用Command←组合键...