【问题标题】:How to safely trigger stage.invalidate()?如何安全地触发 stage.invalidate()?
【发布时间】:2011-09-13 13:05:48
【问题描述】:

我有一个可视化组件,它应该在更新后重绘,而不是立即重绘,而是在屏幕刷新之前。我成功使用了Event.RENDER

我遇到了一个问题,如果我的组件是从另一个组件的渲染处理程序中更新的,那么必要的 stage.invalidate() 命令会被 Flash 忽略。

这是有趣的代码。 主类

public class StageInvalidateTest extends Sprite {
    private var _c : Component;

    public function StageInvalidateTest() {
        stage.frameRate = 1;
        setTimeout(start, 1000);
    }

    private function start() : void {
        trace ("START", getTimer());

        _c = new Component("C");
        addChild(_c);

        var c2 : Component = new Component("C2");
        addChild(c2);
        c2.update();

        addEventListener(Event.RENDER, renderMain);
        stage.invalidate();
    }

    private function renderMain(event : Event) : void {
        trace ("RENDER main", getTimer());
        removeEventListener(Event.RENDER, renderMain);
        _c.update();
    }
}

组件

public class Component extends Sprite {
    private var _name : String;

    public function Component(name : String) {
        _name = name;
    }

    public function update() : void {
        trace ("UPDATE component", _name, getTimer());
        addEventListener(Event.RENDER, renderComponent);
        stage.invalidate();
    }

    private function renderComponent(event : Event) : void {
        trace ("RENDER component", _name, getTimer());
        removeEventListener(Event.RENDER, renderComponent);
    }
}

这是有趣的输出:

START 1994
UPDATE component C2 1995
RENDER component C2 1996
RENDER main 1996
UPDATE component C 1997

组件C 永远不会被渲染。

问题:

什么是让我的组件能够使用渲染事件的安全方法?


我有两个快速的想法:

1) 使用额外的计时器调用stage.invalidate(),延迟为0(零)。计时器在第一次调用其事件处理程序时停止。渲染发生在更新之后。 组件

public class Component2 extends Sprite {
    private var _name : String;
    private var _timer : Timer;

    public function Component2(name : String) {
        _name = name;
        _timer = new Timer(0);
        _timer.addEventListener(TimerEvent.TIMER, handleTimer);
    }

    public function update() : void {
        trace ("UPDATE component", _name, getTimer());
        addEventListener(Event.RENDER, renderComponent);
        _timer.start();
        stage.invalidate();
    }

    private function handleTimer(event : TimerEvent) : void {
        trace ("--- --- TIMER", _name, _timer.currentCount, getTimer());
        _timer.stop();
        event.updateAfterEvent();
        stage.invalidate();
    }

    private function renderComponent(event : Event) : void {
        trace ("RENDER component", _name, getTimer());
        _timer.stop();
        removeEventListener(Event.RENDER, renderComponent);
    }
}

输出:

START 2005
UPDATE component C2 2006
RENDER component C2 2007
RENDER main 2007
UPDATE component C 2008
--- --- TIMER C 1 2021
RENDER component C 2022

看起来很漂亮,正是我想要的。及时嵌套渲染。但我从未见过人们使用这种方法。相反,他们坚持进入框架。使用这样的计时器是否有注意事项或副作用?计时器事件处理程序是否能够在任何情况下触发stage.invalidate,或者是否有预期的副作用?

2) 使用 ENTER_FRAME 事件而不是计时器。缺点:帧率可能较低,渲染可能会延迟。

组件

public class Component3 extends Sprite {
    private var _name : String;

    public function Component3(name : String) {
        _name = name;
    }

    public function update() : void {
        trace ("UPDATE component", _name, getTimer());
        addEventListener(Event.RENDER, renderComponent);
        addEventListener(Event.ENTER_FRAME, enterFrame);
        stage.invalidate();
    }

    private function enterFrame(event : Event) : void {
        trace ("--- --- ENTER_FRAME", _name, getTimer());
        renderComponent(event);
    }

    private function renderComponent(event : Event) : void {
        trace ("RENDER component", _name, getTimer());
        removeEventListener(Event.RENDER, renderComponent);
        removeEventListener(Event.ENTER_FRAME, enterFrame);
    }
}

输出:

START 1994
UPDATE component C2 1995
RENDER component C2 1996
RENDER main 1996
UPDATE component C 1997
--- --- ENTER_FRAME C 2994
RENDER component C 2994

清楚地表明,C 的渲染延迟了 1 sek。


再次提问:

什么是让我的组件能够使用渲染事件的安全方法?

【问题讨论】:

  • 我删除了 Flex 标签,因为这个问题中没有任何特定于 Flex 的内容。
  • Flex 的特殊之处在于该问题也由 Flex LayoutManager 处理,因此希望订阅 Flex 标签的 Flex 开发人员熟悉。
  • 问题的内容中没有提到 Flex 或基于 Flex 的类 [包括 layoutMAnager 类]。如果您想编辑它以包含该区别和/或使用 Flex 重新标记它;我不会在这件事上与你争吵。
  • 不用担心,只是想澄清一下我确实有意识地设置了标签。
  • 不应在渲染处理程序中调用 invalidate;我很确定这是设计使然。

标签: flash actionscript-3


【解决方案1】:

没有什么安全的,Adobe 仍然不关注这个错误。这就是为什么多年来每个人都使用 ENTER_FRAME 和 RENDER 事件。为什么要问?)您不是 AS3Commons-UI 的创建者吗?

顺便说一句,最近向你发送了 Skype 授权,你在吗?

【讨论】:

  • 我很确定这是“设计使然”,因为不应从渲染事件处理程序中调用 invalidate。
猜你喜欢
  • 1970-01-01
  • 2021-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
相关资源
最近更新 更多