类似C#中自定义事件需要一个自定义的EventArgs子类一样,AS3也需要开发者自定义一个Event类的子类,这里我们假设一种场景:设计一个Person(人物)类,里面有Age(年龄),Name(姓名),我们希望每当Person类的实例Age(年纪)发生变化时,能触发一些自定义事件,从而调用某些特定的处理方法。
1.先设计Event类的子类AgeChangeEvent
package {import flash.events.Event;public class AgeChangeEvent extends Event {public static const AGE_OUT_OF_RANGE:String="AGE_OUT_OF_RANGE";public static const AGE_CHANGE:String="AGE_CHANGE";public function AgeChangeEvent(eventType:String){super(eventType);}}}
这里我们定义了二类事件:年龄变化(AGE_CHANGE)、年龄超出范围(AGE_OUT_OF_RANGE)
2.再来设计Person类
package {import flash.display.Sprite;public class Person extends Sprite {private var _age:uint;private var _personName:String;public function Person(personName:String,age:uint) {this._age=age;this._personName=personName;}//将_age封装成属性public function get Age():uint{return _age;}//Age属性的setter方法(在这里加入事件派发处理)public function set Age(age:uint):void{if (age!=this._age){var _ageChangeEvent1:AgeChangeEvent = new AgeChangeEvent(AgeChangeEvent.AGE_CHANGE);dispatchEvent(_ageChangeEvent1);//触发Age改变事件}if (age>=120){var _ageChangeEvent2:AgeChangeEvent = new AgeChangeEvent(AgeChangeEvent.AGE_OUT_OF_RANGE);dispatchEvent(_ageChangeEvent2);//触发Age超过正常范围事件}this._age = age;}//覆盖父类的toString方法public override function toString():String{return "“" + this._personName + "”童鞋一晃今年都已经“" + this._age + "”岁了,真是岁月不饶人啊.";}}}
注意这里的dispatchEvent处理部分,先定义一个事件(参数)对象,然后派发事件.(类似C#中的委托/事件机制,Person类并不知道最终Peson的使用者将如何处理这二个事件,但只要遵守约定就能正确调用开发者执行的处理方法)
3.测试刚才的事件,新建一个Flash File(ActionScript3.0)的fla文件,在第一帧写入以下测试代码 :
var jimmy:Person = new Person("菩提树下的杨过",30);trace(jimmy.toString());jimmy.Age = 31;//现在还没注册任何事件,所以啥也不会触发//注册事件jimmy.addEventListener(AgeChangeEvent.AGE_CHANGE,AgeChangeHandler);function AgeChangeHandler(e:AgeChangeEvent):void{trace("注意:这家伙年龄改了!");}jimmy.Age = 32; //现在改变年龄时,将触发AgeChangeHandler事件jimmy.Age = 150; //将再次触发AgeChangeHandler事件//再注册一个事件jimmy.addEventListener(AgeChangeEvent.AGE_OUT_OF_RANGE,AgeOutOfRangeHandler);function AgeOutOfRangeHandler(e:AgeChangeEvent):void{trace("注意:这老家伙居然说自己年龄超过120岁了!");}jimmy.Age = 149;//将同时触发AGE_CHANGE与AGE_OUT_OF_RANGE事件
建议大家先猜猜结果,动手实践一下,再看下面的输出结果:
“菩提树下的杨过”童鞋一晃今年都已经“30”岁了,真是岁月不饶人啊.
注意:这家伙年龄改了!
注意:这家伙年龄改了!
注意:这家伙年龄改了!
注意:这老家伙居然说自己年龄超过120岁了!
有时候,我们还希望AgeChangeEvent参数还能附带一些额外信息,这个也难不倒AS,把AgeChangeEvent改造一下(注意新增部分):
package {import flash.events.Event;public class AgeChangeEvent extends Event {public static const AGE_OUT_OF_RANGE:String="AGE_OUT_OF_RANGE";public static const AGE_CHANGE:String="AGE_CHANGE";//新增部分private var _OldAge:uint,_NewAge:uint;public function AgeChangeEvent(eventType:String,oldAge:uint,newAge:uint){this._OldAge = oldAge;this._NewAge = newAge;super(eventType);}public function get OldAge():uint{return _OldAge;}public function get NewAge():uint{return _NewAge;}}}
Person类里Age的setter部分也要改一下:
//Age属性的setter方法(在这里加入事件派发处理)public function set Age(age:uint):void{if (age!=this._age){var _ageChangeEvent1:AgeChangeEvent = new AgeChangeEvent(AgeChangeEvent.AGE_CHANGE,this._age,age);dispatchEvent(_ageChangeEvent1);//触发Age改变事件}if (age>=120){var _ageChangeEvent2:AgeChangeEvent = new AgeChangeEvent(AgeChangeEvent.AGE_OUT_OF_RANGE,this._age,age);dispatchEvent(_ageChangeEvent2);//触发Age超过正常范围事件}this._age = age;}
测试fla中的代码稍加改动:
var jimmy:Person = new Person("菩提树下的杨过",30);trace(jimmy.toString());jimmy.Age = 31;//现在还没注册任何事件,所以啥也不会触发//注册事件jimmy.addEventListener(AgeChangeEvent.AGE_CHANGE,AgeChangeHandler);function AgeChangeHandler(e:AgeChangeEvent):void{trace("注意:这家伙年龄从" + e.OldAge +"改成" + e.NewAge + "了!");}jimmy.Age = 32; //现在改变年龄时,将触发AgeChangeHandler事件jimmy.Age = 150; //将再次触发AgeChangeHandler事件//再注册一个事件jimmy.addEventListener(AgeChangeEvent.AGE_OUT_OF_RANGE,AgeOutOfRangeHandler);function AgeOutOfRangeHandler(e:AgeChangeEvent):void{trace("注意:这老家伙居然说自己年龄超过120岁,现在已经有" + e.NewAge + "了!");}jimmy.Age = 149;//将同时触发AGE_CHANGE与AGE_OUT_OF_RANGE事件
新的输出结果:
“菩提树下的杨过”童鞋一晃今年都已经“30”岁了,真是岁月不饶人啊.
注意:这家伙年龄从31改成32了!
注意:这家伙年龄从32改成150了!
注意:这家伙年龄从150改成149了!
注意:这老家伙居然说自己年龄超过120岁,现在已经有149了!
后记:自定义事件可以广泛应用于很多场景,比如我们可以自己做一个控制滑块MovieClip,里面定义一个ValueChange事件,其它需要的地方(比如音量大小控制,对象Alpha值控制,对象大小控制...),只要定义自己的处理函数,然后注册到该事件即可
源代码:/yjmyzz/as3_custom_events.rar
最后做为对比和复习,贴出C#版的自定义事件:
AgeChangeEventArgs类
using System;namespace EventDemo{public class AgeChangeEventArgs:EventArgs{private uint _oldAge;private uint _newAge;public AgeChangeEventArgs(uint oldAge, uint newAge) {this._oldAge = oldAge;this._newAge = newAge;}public uint OldAge { get { return _oldAge; } }public uint NewAge { get { return _newAge; } }}}
Person类
namespace EventDemo{public class Person{public delegate void AgeChangeEventHandler(object sender, AgeChangeEventArgs e);public event AgeChangeEventHandler AgeChangeEvent;public event AgeChangeEventHandler AgeOutOfRangeEvent;private uint _age;private string _name;public uint Age{get { return Age; }set{if (value != _age){if (AgeChangeEvent != null){AgeChangeEvent(this, new AgeChangeEventArgs(_age, value));}}if (value >= 120){if (AgeOutOfRangeEvent != null){AgeOutOfRangeEvent(this, new AgeChangeEventArgs(_age, value));}}_age = value;}}public string Name{get { return _name; }set{_name = value;}}public Person(string pName, uint pAge){this._age = pAge;this._name = pName;}public override string ToString(){return "“" + this._name + "”今年已经“" + this._age + "”岁了!";}}}
测试程序:
using System;namespace EventDemo{class Program{static void Main(string[] args){Person p = new Person("菩提树下的杨过", 30);Console.WriteLine(p.ToString());p.Age = 31;p.AgeChangeEvent += new Person.AgeChangeEventHandler(p_AgeChangeEvent);p.Age = 32;p.AgeOutOfRangeEvent += new Person.AgeChangeEventHandler(p_AgeOutOfRangeEvent);p.Age = 150;Console.ReadKey();}static void p_AgeOutOfRangeEvent(object sender, AgeChangeEventArgs e){Console.WriteLine("天啊,这家伙的年龄居然已经达到" + e.NewAge + "岁了!");}static void p_AgeChangeEvent(object sender, AgeChangeEventArgs e){Console.WriteLine("注意:这家伙的年龄从" + e.OldAge + "岁改成了" + e.NewAge + "岁!");}}}