为什么updateDisplayList在Flex中停止发生?

时间:2010-07-30 15:48:34

标签: flex

奖励:已声明。

概述:此处部署了解决问题的代码:http://www.johnuckele.com/MastersOfTime.html

我遇到的问题是某些操作序列(我不完全理解如何或为什么)导致我对invalidateDisplayList的调用无法生成对updateDisplayList的后续调用。我所知道的是,在此期间,其他一些视觉效果将无法发生(例如更改组件的宽度或添加新的孩子)。

示例:下面的程序会绘制两列水平线。在commitProperties期间绘制左侧的列,在updateDisplayList期间绘制右侧的列。某一系列操作可能导致右列停止更新。

要触发此错误:首先添加一个新项目。现在点击开始按钮,一个栏开始填满。如果按添加行按钮,则右列和填充栏都会停止生长。左栏继续不受约束。直到TEComputeRow.tick()中if语句的最后一行不为帧执行时才会出现额外组件。单击停止按钮以停止执行TEComputeRow.tick()中if语句内的块,一切都恢复正常。

问题:这里发生了什么?

我现在可以通过使用验证来强制它行为,但它不能解决问题,它只是覆盖了一帧。它似乎也是一个非常草率的黑客。有没有比使用validateNow更好的方法来处理updateDisplayList的丢失?有没有办法准确识别世界状况?

MastersOfTime.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    backgroundColor="white"
    backgroundGradientAlphas="[1,1]"
    initialize="init()"
    enterFrame="tick()"
    creationComplete="addComputeArray()">
    <mx:Script>
        <![CDATA[
            import mx.containers.HBox;
            import mx.controls.Button;
            import mx.containers.VBox;
            import flash.utils.getTimer;
            private var global:int = 0;

            private function addComputeArray():void
            {
                var addButton:Button = new Button;
                addButton.label = "Add Row Item";
                addButton.addEventListener(MouseEvent.CLICK, addComputeBox);
                box.addChild(addButton);
            }

            private function addComputeBox(a:* = null):void
            {
                box.addChild(new TEComputeRow());
            }

            private function init():void
            {
                box.clipContent = false;
                box.graphics.lineStyle(1);
            }

            private function tick():void
            {
                global++;
                this.invalidateDisplayList();
                this.invalidateProperties();
                //this.validateNow();
            }
            protected override function commitProperties():void
            {
                super.commitProperties();
                box.graphics.moveTo(100, (global*3)%800);
                box.graphics.lineTo(200, (global*3)%800);
            }
            protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
            {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
                box.graphics.moveTo(200, (global*3)%800);
                box.graphics.lineTo(300, (global*3)%800);
            }
        ]]>
    </mx:Script>
    <mx:VBox id="box"/>
</mx:Application>

TEComputeRow.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
    height="60"
    width="352"
    verticalGap="0"
    borderStyle="solid"
    enterFrame="tick()">
    <mx:Script>
        <![CDATA[
            public var doStuff:Boolean = false;
            private var parameter:Number = 0;

            private function tick(e:Event = null):void
            {
                var value:*;
                if(doStuff)
                {
                    parameter = parameter+1;

                    value = parameter;

                    fill.width = value;
                }
            }
        ]]>
    </mx:Script>
    <mx:Button label="turn on" click="{doStuff = true;}" height="20"/>
    <mx:Container id="fill" x="7" width="0" height="20" backgroundColor="0x8888AA"/>
    <mx:Button label="turn off" click="{doStuff = false;}" height="20"/>
</mx:VBox>

2 个答案:

答案 0 :(得分:5)

对于初学者来说,你正在疯狂地滥用Flex生命周期,并做你不打算做的事情......改变行的勾号中的填充宽度启动另一个无效循环是一个马上跳出来。如果你通过计时器而不是在enterFrame上开车,你会立即变得更好。

我的猜测是你每帧花费这么多时间重新使属性失效(改变宽度会使属性无效),玩家永远不会适应updateDisplayList。

了解Flex 3生命周期中的elastic race trackDeepa's presentation

答案 1 :(得分:0)

使用.width是触发此问题的原因。如果我用.setActualSize替换.width,问题就会停止。这些代码片段通过不同的路径传递.width和.height显然有能力跳过部分帧周期(updateDisplayList部分)。