定制复合控制不能正确渲染只有0.5-1秒被重新添加到一个VGROUP后(Custom Composi

2019-06-25 12:51发布

我正在从MXML路程,已经建立了ActionScript中的自定义组件的控制。

我有控制正确显示。 这个问题是在我从显示列表中删除,并与.addElement(控制)方法重新添加回。

下面是增加了再次插入的代码。

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无法正常渲染。 该plusIcon按钮内_btnMultiple是不是第一次正确postioned,但随后迅速纠正自身0.5-1秒后。

我敢肯定,问题在于内comboBoxMultiSelect,只是不知道如何强制图标留在同一个地方。

这是经过我所有的努力非常恼人的,任何人有想法,我做错了什么?

谢谢 :)

UPDATE ----->这里是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, this, true));
    }

    public function addSelfToValueObject(valueObject:Object):Object{
        valueObject[AmfPHPArgumentName] = _selection;
        return valueObject;
    }

}

Answer 1:

我会尽力给你什么,我与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(请注意,它也可以扩展你的ReportControl是否会延长SkinnableComponent而不是UIComponent)。

[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完全匹配。 由于required设置为true编译器会检查是否这些组件的皮肤真的存在。 如果你想选购皮肤的部位,将它设置为false
  • 需要注意的是类型toggleButtonIEventDispatcher :从视主机组件的角度来看,所有的toggleButton所要做的,是调度单击事件。 这意味着我们现在可以创建与皮肤<s:Image id="toggleButton" source="..." />整个事情将继续努力以同样的方式。 看到强大这是什么?
  • 因为skinpart性质不立即分配,我们覆盖partAdded()每当一个部件变得可用将被执行的方法。 在大多数情况下,这是你挂钩的事件侦听器的地方。
  • toggleExpanded()方法中,我们切换布尔就像在你的问题的组成部分,但我们只无效的皮肤状态。 这将导致皮肤调用getCurrentSkinState()方法,并更新其状态返回的任何值。

等瞧! 你必须与行为的工作组件很好地分离成ActionScript类,你不必担心布局错综复杂。 而如果你想创建一个具有相同行为的一个组成部分,但它应水平而不是垂直扩展:只要创建一个新的皮肤,调整width ,而不是的height并分配到同一主机组件。

等一下! 我差点忘了告诉你如何给肌肤组件分配。 你可以这样做内联:

<c:ComboBoxMultiSelect skinClass="my.skins.ComboBoxMultiSelectSkin" />

或者通过造型:

@namespace c "my.components.*";

c|ComboBoxMultiSelect {
    skinClass: ClassReference("my.skins.ComboBoxMultiSelectSkin")
}


Answer 2:

脱颖而出的一件事是在你执行updateDisplayList() 如你所知,这是你的组件应该大小和位置,它的子对象(和/或做任何程序上的图)。

但是,而不是直接设置子对象的宽度/高度,你应该使用Flex的生命周期方法之一: setActualSize()setLayoutBoundsSize() 使用setLayoutBoundsSize()与Spark组件。

当您设置一个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被赋予了percentWidth,但在updateDisplayList()它被赋予一个固定的宽度(这可能是一个红色的鲱鱼,但我不会设置该percentWidth)。

2)你也许可以给组件欺骗验证自身删除,或者你之前重新添加它之后。 哈克预感,可能是在浪费时间。

3)从组件移除“HGroup”。 这是一种不必要的:布局要求是很简单的做瓦特/的Actionscript几行。 作为布局的要求变得越来越复杂您的里程可能会有所不同!

createChildren()直接添加组合框和按钮的UIComponent 。 然后,大小和位置他们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);
}


Answer 3:

谢谢你们两个了您的回答! 在解释这些概念的考虑和对细节的关注是真棒! TRES边!

@RIAstar然而,由于代码量已经到位,改变我的架构(从行为分离的视觉元素)将强制代码的大型重因子,将花费得多了尚未明确要求的特性。 (控制能够在运行时更改的视觉表现)这当然是有趣,我会补充说,到未来的版本。

不过,我想我已经能够找到一个解决我的问题。 我决定建立关@ SunilD的公司。它加回之前验证控制的建议。一劈我知道,但人是不完美的,因此代码AINT无论是。 ;-)

当在控制看,我发现这是只有在和渲染自己的形象问题的按钮。 所以测试,我添加与删除图标只是一个按钮实例,我看到相同的行为! (不论comboBoxMultiSelect是如何实现的),我注意到,我没有看到该按钮做到这一点时,首次建立它。 因此,当它被从显示列表中删除,为什么不只是重建按钮?

我结束了布线comboBoxMultiSelectFlexEvent.REMOVE事件,破坏按钮参考,创建一个新的,用的AddChild添加它()。 以下是该事件的解释。

如果该组件从容器通过使用除去作为非内容子组件时从容器中作为内容子使用removeChild(),removeChildAt(),removeElement()或removeElementAt()方法去除“调度。 rawChildren.removeChild()或rawChildren.removeChildAt()方法,则不会分派该事件。

该事件仅当有一个或连接到分派对象多个相关侦听器“。

果然,这个固定的显示不正确的图标,并解释了发生的事情。 出于某种原因,该按钮服用一种以上渲染事件申请时,它添加回它的风格。任何人能够复制这种行为?

我想现在真正的问题是“什么是最好的方式来删除和添加回式的按钮显示列表,以便其嵌入的图标是不会受到影响?”



文章来源: Custom Composite Control not rendering correctly for only 0.5-1 sec after being added back into a VGROUP