(2012-01-08 旧博文搬运)[EssentialActionScript3.0中文版]无责任翻译-21章事件与显示层级(4)

17 篇文章 0 订阅

21.7. 停止一个事件的派送

在事件流的任何点,每个事件侦听器——包括哪些注册在目标对象上的以及注册在他们的父级对象上的——都可以停止整个事件的派送。停止一个事件的派送被归类为事件的毁灭. 要停止一个事件派送,我们在被传递了Event对象的侦听器函数中调用Event 类的实例方法stopImmediatePropagation()或者stopPropagation()。

stopImmediatePropagation() 方法可以立刻停止事件派送,不让剩余的侦听器继续被调用;而stopPropagation() 方法会在AS调用完剩余的已注册的注意到这个事件的侦听器之后停止事件派送.

 

比如,假设我们有一个Sprite 容器, 他包含了一个TextField 子级.

var container:Sprite = new Sprite();

var child:TextField = new TextField();

child.text = "click here";

child.autoSize = TextFieldAutoSize.LEFT;

container.addChild(child);

 

更进一步假设我们有3个事件侦听器函数:

containerClickListenerOne()containerClickListenerTwo(), 以及 childClickListener(). 我们在容器上注册containerClickListenerOne()and containerClickListenerTwo()来响应捕获阶段的MouseEvent.CLICK 事件

container.addEventListener(MouseEvent.CLICK ,containerClickListenerOne,true);

container.addEventListener(MouseEvent.CLICK ,containerClickListenerTwo,true)

;

然后我们注册给子类childClickListener() 来侦听目标阶段的MouseEvent.CLICK事件

child.addEventListener(MouseEvent.CLICK,childClickListener, false);

 

一般情况下,当用户点击child, 这3个事件侦听器都会执行——2个是在捕获阶段,一个是在目标阶段。但是如果containerClickListenerOne()通过stopImmediatePropagation()摧毁了事件,那么不管是containerClickListenerTwo() 还是 childClickListener() 都不会执行了.

public function containerClickListenerOne (e:MouseEvent):void {

// 阻止containerClickListenerTwo() 和childClickListener() 对事件做出反应

e.stopImmediatePropagation();

}

 

另一方面,如果containerClickListenerOne()使用的是stopPropagation() 而不是stopImmediatePropagation(), 那么容器container的其他MouseEvent.CLICK 事件侦听器在事件停止之前仍然会执行。因此containerClickListenerTwo()也会接受到事件,不过childClickListener()不行

 

public function containerClickListenerOne (e:MouseEvent):void {

// 仅仅阻止childClickListener()对事件做出响应

e.stopPropagation();

}

 

 

注意在前面的代码是依托了containerClickListenerOne() containerClickListenerTwo()之前注册。更多信息有关哪个侦听器被执行,请看Chapter 12.

 

 

 

 

事件一般在需要停止的时候或者可能会颠覆一个应用程序的正常事件响应的时候被摧毁。比如,假设有一个Sprite 的子类, ToolPanel, 包含了一组界面控制元件,每个都承担了用户输入。这个

ToolPanel 类有2个运作状态:激活状态与不可用状态。当一个ToolPanel 对象处于不可用状态时,用户不应该与它的内嵌界面控制元件发生互动。

 

 

要实现这个"不可用" 状态, 每一个 ToolPanel对象都注册一个方法, clickListener(), 用来侦听捕获阶段的MouseEvent.CLICK事件。当一个ToolPanel 对象处于不可用时, clickListener() 方法会停止所有的通往子级Tool对象的点击事件。

 

 

Example 21-3 展示了ToolPanel 类, 用粗体强化了摧毁事件代码。在此例中,ToolPanel类的子级界面控制元件是一个一般的Tool 类的实例,这里没有写出来。但是在一个真实的应用程序中,这个控制元件可能是一个按钮、菜单或者其他互动工具.

 

 

 

 

 

Example 21-3. 摧毁一个事件


 

在典型的应用程序开发中, stopPropagation() 方法使用的比stopImmediatePropagation() 频繁。虽然如此,stopImmediatePropagation() 方法依然会在下面情况中被使用:

• 当一个目标对象希望阻止属于他自己的侦听器被一个事件调用

• 当一个程序希望阻止所有的侦听器应答某个给定的事件

 

我们来为这2中情况考虑例子。先来考虑第一条,一个目标对象想要停止属于他自己的侦听器被一个事件调用。假设一个太空射击游戏包括了下面的类:

• GameManager, 一个管理游戏的类

• PlayerShip, 一个代表了玩家的宇宙飞船的类

 

GameManager 定义了一个自定义事件GameManager.SHIP_HIT, 它会在敌人的子弹射中玩家的飞船时发送。每一个GameManager.SHIP_HIT事件发送的目标都是PlayerShip对象. 

PlayerShip 对象注册了2个侦听器来响应GameManager.SHIP_HIT 事件。一个侦听器播放爆炸动画,另外一个播放爆炸声音。

 

当玩家死亡时,一个新的玩家飞船会被创建,这艘新飞船会有5秒无敌时间。在无敌状态, PlayerShip 对象的 GameManager.SHIP_HIT 侦听器不应当播放“飞船爆炸”的动画或者声音。

要阻止GameManager.SHIP_HIT 侦听器在飞船无敌的时候执行, PlayerShip 类要注册第三个侦听器hitListener(), 通过飞船的状态决定是否摧毁 GameManager.SHIP_HIT 事件。这个hitListener() 方法在PlayerShip的构造函数中被注册,这样他就有最大(int.MAX_VALUE)优先权,如下:

public class PlayerShip {

public function PlayerShip () {

addEventListener(GameManager.HIT, hitListener, false,int.MAX_VALUE);

}

}

 

在 Chapter 12 我们学习了,默认情况下,一个对象的事件侦听器们会以他们被注册的先后顺序被调用。我们也学到了这个默认的“调用顺序”可以通过设置addEventListener()的 priority 属性来改变.

 

由于 hitListener() 是在PlayerShip 的构造函数中注册的,它拥有最高优先级,当

PlayerShip 的 GameManager.SHIP_HIT 事件发生,它是第一个被调用的。当飞船对象不是无敌状态,并且一个 GameManager.SHIP_HIT 事件发生了, hitListener() 不会做任何事。但是当飞船处于无敌状态并且发生了GameManager.SHIP_HIT 事件, hitListener() 会第一个摧毁这个事件,然后发送一个新事件: PlayerShip.HIT_DEFLECTED. 注册PlayerShip.HIT_DEFLECTED事件的侦听器就会播放一段特殊的动画和声音表示飞船没有受到伤害。

 

hitListener() 的代码如下;注意stopImmediatePropagation()方法的使用.

private function hitListener (e:Event):void {

if (invincible) {

// 阻止其他飞船侦听器接受事件通知

e.stopImmediatePropagation();

// 广播一个新事件

dispatchEvent(new Event(PlayerShip.HIT_DEFLECTED, true));

}

}

 

在前面的这个PlayerShip 例子里,要注意虽然PlayerShip 对象可以阻止他自身具有的侦听器

GameManager.SHIP_HIT被调用,但是它无法阻止那些注册在它的父级显示对象上的GameManager.SHIP_HIT 侦听器。明确地说,任何注册在PlayerShip父级对象的捕获阶段的侦听器都会收到GameManager.SHIP_HIT 事件的通知,即使PlayerShip 对象摧毁了这个事件。但是,在PlayerShip 摧毁GameManager.SHIP_HIT 事件之后,它的父级们将不会在冒泡阶段收到事件通知。

 

现在,我们转到第二种使用stopImmediatePropagation() 的情况, 这种情况下,程序想要阻止所有的对某个特定事件的响应。假设我们写了一个UI组件,这个UI会在FP丢失OS焦点的时候变为“不活动”状态,而在FP重新获得OS焦点的时候转为“活动”状态。为了检测OS焦点的得失,我们的UI组件注册了一个内置事件Event.ACTIVATE和 Event.DEACTIVATE的侦听器。

(有关 Event.ACTIVATE和Event.DEACTIVATE的详细信息, see Chapter 22).

 

现在进一步假设我们写了一个测试程序来强调我们UI组件的测试。我们的强调测试程序程序化地调用UI组件的交互行为。在我们的测试中,我们必须保证内置事件Event.DEACTIVATE 不会使测试组件变的不活动;否则,我们的测试程序将不能程序化地调用他们。因此,在我们的测试程序的主类构造函数里,我们在Stage实例注册一个Event.DEACTIVATE 侦听器。这个侦听器使用stopImmediatePropagation()来摧毁所有的Event.DEACTIVATE内置事件, 如下:

private function deactivateListener(e: Event):void {

e.stopImmediatePropagation();

}

 

因为我们的测试程序摧毁了所有 Event.DEACTIVATE 时间,那么组件就不会收到Event.DEACTIVATE 通知,也就因而不会作为对FLASH运行时丢失系统焦点的响应而变为不活动状态。测试程序的管理者就可以程序化地在测试运行的时候对FLASH运行给予焦点或移除焦点,而不受测试程序对组件控制能力的影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值