-
有些朋友说,看到弧度我就晕——糊涂。其实这是因为我们对它,还不太熟悉、理解的缘故。以前我们也常说:看到AS我就晕。通过学习对AS比较熟悉、理解了,也就不那么晕了。为此我想谈谈有关弧度的问题。也许能对有些朋友有一点帮助。
一、角的两种单位
“ 弧度”和“度”是度量角大小的两种不同的单位。就像“米”和“市尺&rdq... -
我们都知道,横波是一种正弦波,那么我们就要模拟出来一个正弦的波的形状.
下面说一下它的制作过程及原理.
原理:使用正弦函数控制每个小球在竖直方向的运动,用复制函数来复制相同的小球在不同的水平位置.
制作过程:
1、先做一个小球,我们可以用线性渐变,做一个有一定立体感的小球。转换为mc
2、新建一个mc,命名为ss,把刚才做好的小球mc拖入场景,调整它的位置到正中间。在小球mc上加上如下代码:
onClipEvent(load){ //小球载... -
在学习三角函数之前,我们先来了解一个概念---弧度
在日常生活中我们使用的度量角度的单位是度。一个圆周是360度,但是这个数字是任意规定的。而弧度单位是数学家们定义的测量角度的标准公制单位。弧度是基于π定义的,π是圆的一种固有属性。计算机编程语言通常在处理角度时都以弧度为单位。flash as的内置Math类,它在计算时都是以弧度为单位。
弧度的定义如下:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时,两条射线的夹角的弧度为1。... -
最近总用一些朋友问起一些数学公式,说这些内容不会,所以在这里开一个基础教程,希望能够对大家的学习提供帮助.
在flash中,Math类是一个非常常用的类,通过数学计算,可以实现很多非常美妙的效果,我们在这里从最基础的学起,补一补数学知识.
我们先来看看flash中提供的Math类吧:
Math.abs() 计算绝对值。
Math.acos() &n... -
美妙的Timer类——Timer与时钟Timer绝对是as3改进的亮点之一。它的使用技巧和美妙之处不是一下能说完的。这里先对它进行个完整的说明,再举几个具有启发的例子。为初学者处理计时器打下牢固的基础。
Timer类:
Timer类继承EventDispatcher。是FlashPlayer计时器接口。计时器可以用来间隔调用和延时调用。在其过程中可以访问其状态甚至进行干预。以此塑造出来的灵活性足以替代as2中的setInterval和getTi... -
再述冒泡
思路
1 在as2中发现问题,
2 在as3中解决问题。
3 结合问题,说明冒泡
4 冒泡的问题所在以及解决方法
冒泡很多人在谈,前段时间小弟也是一知半解。弄得云里雾里的。
最近找到一个pdf,呵呵,才算弄明白了点。
把一点学习笔记发出来。
1 在as2中发现问题,
我们用一个例子来发现as2中究竟有什么问题。
As2中实现如下效果:
舞台上一个m... -
Document Class初始化 > 主时间轴代码执行 > 舞台元件绑定的类初始化 > 元件的时间轴代码初始化 >..
下面的层次按这样的规律循环。
-
1、组件的parentApplication属性包含此组件的Application对象,Application对象本身的parentApplication为null。当Flex程序生成的SWF文件被其他的Flex程序加载时,被加载的Flex程序中组件的parentApplication属性保持不变,这种情况下,parentApplication属性有可能代表主程序
组建还有两个相关属性:parent属性,指包含组件的父级对象;parentDocument属性,指组... -
1、ComboBox,重点理解DropdownEvent事件。在列表被弹出或收回时,会分别派发DropdownEvent对象的OPEN事件和CLOSE事件。对这两个时间进行监听,便可捕捉用户的动作。
2、注意,与之外的都是一个整体,而不是分开的
3、发现还有很多人不明白这个void为什么要加。这里说明一下:是为了方便不带参的function除错(debug)。例如:... -
flex builder 2编译时下正常的flash9.ocx的问题解决
前些天了解到flash9的安装占有已达近于40%了,所以想抽些时间多接触一下AS3.0,之前使用的多为flex 2 sdk, 但并不是舒服,所以想选择一种编程调试环境,经过比较一种是flashdevelop.org的flashdevelop 另一种就是flashbuilder2 ,尽管看上去flashdevelop看上去要比简洁一些,但要想让As3.0很顺畅的运行起来,是要安装些东西,并需要进行一些配置, 最终选择了flex builder 2. flexbuilder 2 用来编译as3.0也还算... -
AS3.0教程(11): 视觉元件精要(1) 来源:
http://www.kingda.org/archives/kingda/2006/11/as3011_1.html#more
作者:黑羽(KingdaSun)
彻底了解AS3视觉元件架构
DisplayObject,直译为视觉对象,意为可以被看到的对象。
视觉是Flash 成功的主要基石。当我赏析Actionscript 3 的所有视觉元件类型和其整体构架时,感到非常满意。可以看出,这次整体的架构设计是深思熟虑的结果。与其他语言,比如C#,相比有自己强烈的特色,是对Flash视觉行为贴身定做的结果。
Actionscript 3的架构乍一看很复杂,不包括UIComponent的子类,就有7到8个层,20多个莫名奇妙的类。头疼!但实际上,它的设计是非常的简洁优雅,远远比Actionscript 2一个MovieClip打天下强太多了。实际上,只要真正弄清了它的设计思路,就可以高屋建瓴,一览无余,会发现这个架构逻辑清晰,非常的易懂易记。所以,先抛开Actionscript 3 的帮助文件,我们一起来看看为什么要设计这样一个架构,搞出20多个怪胎出来。
先来追忆一把Actionscript 2中无所不能的先贤: MovieClip(影片剪辑)。 这位兄台无所不能:可在其中画矢量图,可在其中贴位图;可在其中做影片,也可嵌套子影片;偶尔用来加载,闲来客串按钮;三教九流皆可放,肚皮天下第一广。它的父亲何人,原来是元始天尊Object。
这样的玩意儿,新手用起来很爽,大大节约了脑细胞。但任何一个有过大型OOP项目经验的老手,都会毫不犹豫的指出,这样的架构设计是失败和混乱的。代价是巨大的。MovieClip类公开的属性和方法共有一百多个(自己数数)!居然直接继承根类!居然拥有这样多公开(public)属性和功能的类!居然应用范围如此广泛!
首当其冲,其第一弱点就是系统资源的浪费。
举个例子, 我新建一个空MovieClip A,只是想让它做个容器,好在里面放几个有内容子MC。这样我操作A的位置和渐变时,子MC会统一变化。这样的经验大家都有吧。可就是这么一个简单的纯容器A,Actionscript 2&1都会毫不犹豫的把MovieClip所有的属性和方法都赋给A。谁让A是MovieClip类的实例呢?可在这个应用上,我们要A的其他90多个功能干什么呢?而且还不算最耗资源的内建的对Timeline的支持!大家想想,我们每天都在创建MC。但事实上我们做开发时,创建的MC有多少用到了大部分的功能和Timeline?只有一部分的通过Flash创建的MovieClip才需要时间轴的支持,其余大部分根本不需要时间轴支持。这样的设计是不是有问题呢?
痛批了一顿Actionscript 3之前的MC后,我们不得不说几句公道话:这样的错误是有其历史局限性的,我们不能苛求古人。且看现在的视觉元件架构,那叫一个爽。爽,就爽在系统设计师对整个Flash视觉系统的抽象上。抽象和解构的功力很深!不得不佩服!系统各个超类和子类的设计划分,职责清晰,稳健高效,堪称优雅!我看.Net FrameWork 的System.Drawing架构设计时都没有这个感觉。毕竟Flash是靠视觉起家,与视觉动画交互打交道最深阿。
下面来欣赏Actionscript 3 的元件架构。
Actionscript 3 中所有可以被看到的视觉元件都统一于DisplayObject,即其子类的实例。DisplayObject是一个抽象类,不能生成实例。从系统架构设计上来说,这样的超类设计是常识。DisplayObject,我在AS3.0教程(5):强大的事件机制(1)中讲过,继承于EventDispatcher类,也就意味着所有的DisplayObject子类都可以发送事件了。
啊哈,DisplayObject下面一层的抽象就精彩了,架构设计师的原意是将所有视觉元件分为两大类:可以接受人机交互事件的,和不可以接受人机交互事件的。所以就有了InteractiveObject类和非InteractiveObject类之分。由于非InteractiveObject的几个类之间差别太大,也抽象不出什么共同点,所以,干脆就分成了InteractiveObject的六个同级兄弟 AVM1Movie, Bitmap, MorphShape, Shape, StaticText, Video。但黑羽认为从系统的优雅性出发,不妨就设一个UnInteractiveObject的超类,将这六个孩子放在这个超类的下面。还便于日后的功能扩展。
在讲最重要的InteractiveObject之前,我们先把这几个不伦不类的兄弟先扫掉。这几个子类中,我们把它分为可以代码创建的,和不可以代码接触的。所谓不可以代码创建的,是指只能通过Flash创作工具来创建的。和以前一样,StaticText还是不可以用代码实现。另外一个是MorphShape,这个东东是指在Flash中创建Shape形变时,由Flash Player自动生成的,同样的,代码无法实现。
剩下的几个都是可以用代码创建的:Bitmap,位图对象,可以通过BitmapData对象来创建,也可以从外部载入,比如通过loader。Shape,形状,专门用来绘制矢量图的,通过Graphic对象创建的。Video,视频对象,专门用来播放视频的,可以来自文件也可以来自网络流媒体。
下面要说到的是AVM1Movie,所谓AVM1Movie,意思就是说Actionscript Virtual Machine 1所支持的SWF影片,也就是Actionscript 1和2的影片。由于Actionscript 3 采用的是AVM2,所以和AVM1影片无法跨脚本交流,必须要把它同AVM2 swf影片区分开来,所以有个这个类。关于这个,感兴趣的兄弟看我的这篇文:小谈Actionscript 3.0与AS 2.0,1.0的swf兼容性。这个一般我们不用关心,也不用直接接触,一旦我们加载一个AVM1老影片到AVM2 swf中时,Flash Player 会自动创建一个AVM1Movie的实例包装这个swf。我们打交道的往往是装载AVM1 swf的容器元件。
到了InteractiveObject下一层了,这一层共有三个类。
这一层的抽象理念又要赞一下。架构设计师又用了一个容器和非容器的概念来区分视觉元件。所谓容器,就是可以在其中加载其他的DisplayObject子类对象。当然也包括它的叔叔们,即非InteractiveObject的那几个类。所谓非容器,那就是说不能在它的视图里面加入其他的DisplayObject了。“容器”,这个公共性质实在太重要了,在这一层才这样抽象出来实在很高明,很到位。
那么老套路,先讲讲非容器的两个类,TextField和SimpleButton。 TextField,就基本上是我们熟悉的动态文本框,这里暂不细说。来说说SimpleButton,这个名字虽然和我们在Actionscript 2中碰到的SimpleButton一样,但实际上二者有很大的差别了。实质上,Actionscript 3 中SimpleButton这个类是将Button这个重要常用的UI控件单独提出作为一类,而不是像以前和MovieClip混淆不清。谁都知道,在Actionscript 2和1中,只要改改MovieClip前几个帧的标签,这个MovieClip就变得和Button一样了。关于SimpleButton的使用,可以说非常简洁实用,这个放在后面细说。我在这里所要强调的是Button和MovieClip不是一个性质。虽然Actionscript 3中Sprite和其子类也可以通过buttonMode来做出和Butoon相似的行为,但原理是不同的。
剩下的就是DisplayObjectContainer类了。DisplayObjectContainer的所有子类对象,都可以在其中添加其他DisplayObject子类对象。但要注意一点,DisplayObjectContainer本身也是一个抽象类,不可以生成实例。这是出于架构设计稳健性扩展性的考虑,和将DisplayObject设计成抽象类的原因一样,不多说了。
重要的是看看它的几个子类,Sprite, Loader, Stage。 Stage,就是舞台,所有的视觉元件都是在它之中,当之无愧是最终容器,放在这一层也是合情合理。 Loader就有趣了,它把以前MovieClip装载的部分全部抽象分离出来了。所有和外部资源的加载,都是通过Loader来进行的。而Loader也不能直接和网络资源打交道,要通过专门的URLRequest对象来进行,各司其职,非常好。Loader能干什么?装载swf, 和各种图片。注意,视频还是要通过Video类来进行,直接addChild到各种Container中,不一定要放在Loader中。
下面来了Sprite,这个3.0中我们打交道最多的容器了。一句话,它是去掉了时间轴的MovieClip(即MovieClip被阉掉了)。如我开头例子所说,倘若我们只是为了创建一个容器,那么Sprite是首选。甚至可以说,我们这些写代码的开发人员,90%以上的情况都只需要和Sprite打交道。含有时间轴的MovieClip一般是Flash工具创建出来的,往往只需要加载就可以了。准确的说,Sprite比Actionscript 2中的MovieClip不止少一个TimeLine,如装载。Sprite中也含有Graphic对象,这意味着,它也可以直接在其中代码绘图。但我们始终要记住,Sprite不同于Shape,区别就在于Sprite是容器,而Shape不是。从代码角度说,就是,Sprite可以addChild(),但Shape不可以。
都说到这儿了,我们亲爱的MovieClip还不见踪影,到底在哪儿了呢?其实就在Sprite的下一层。Sprite下一层中,共有四个子类,MovieClip是其中一个。大家可以想到,现在的MovieClip重要性大不如前了,主要就是代表用Flash创建的含有时间轴的影片。常用的gotoAndStop, currentFrame等等这些属性现在才能碰到了。
其余三个子类,也是来头不小,最牛的就是其中的FlexSprite。虽然它的改动只是变了一下toString()函数,但它却是所有Flex组件的共同基石。著名的UIComponent的老爸现在就是它了。UIComponent何许人也?天下组件,皆由它出。黑羽大胆预测,我们在Flash 9中所要用到的控件,也就是现在的Flex里面的组件,即mx.controls里面的所有组件。此类不可小看。
另两个子类Preloader和DownloadProgressBar,已经不属于flash.display包了,而是属于mx.preloaders包,主要管理的是下载进度和共享库的下载等功能,不予细说了。
到此,Actionscript 3 主要的视觉元件架构已经理出了一个清晰的脉络,设计的原因,理由,思路都做了一一剖析,希望大家喜欢。其实InteractiveObject下的另外两根枝条TextField和SimpleButton也有很重要的地位,在后续教程中会一一细说。
下面到了老鸟时间了,和老鸟们分享一下我对Actionscript 3 视觉架构的分析心得。可以看出的是,抽象的界限非常明确,应用的模式也比较统一。应用的模式就是OOP编程中最常用的模式之一:Composite模式。比如Shape下的Graphic对象,Sprite下面的SoundTransform对象,Loader下的LoaderInfo对象,等等等等。我本来迷惑,为何不用装饰器模式,让这些元件的行为和Actionscript 2更加相似一些,过渡的痛苦少一些,但转念一想明白了架构设计师的苦心。就是要用这样清清楚楚,明明白白的Composite来加强所有开发者OOD时分工协作,更加快的熟悉和运用新的强大的架构。与这个优点相比,这么一点过渡的痛苦又算得了什么呢?
关于Actionscript 3视觉编程后续部分和具体的编程例子,会陆续放出。
P.S:本系列教程受Creative Commons License.协议保护,未经作者同意,不得用于商业用途。 -
AS3.0教程(10):强大的事件机制(6) 来源:
http://www.kingda.org/archives/kingda/2006/08/as30106.html#more
作者:黑羽(KingdaSun)
事件机制写的太多了,我自己都有点烦了。
但没办法,太重要了。而且AS3做了这么多好的改进,值得我们去一一探寻,给我们日后的编程带来极大的便利。Actionscript 初学者,本节可以跳过不看。
Actionscript 2熟练工应当看看,有些价值。
今儿讲掉
4. 合成EventDispatcher进行事件发送。
5. 实现IEventDispatcher接口来进行事件发送。 与设计模式中的装饰器模式相似。
这样事件的发送和接受,就可以讲完了。
那么,事件部分就这样完了?没有!你晕,我也同晕。因为还有一个很重要的特性,Event flow机制还没讲。这就是我所说的事件冒泡机制。给我们编程带来了莫大的方便。
好,下面先讲:
4. 合成EventDispatcher进行事件发送。
什么情况下用合成EventDispatcher来发送Event呢?
一般发生在某个较复杂的类里面。
这个类可能是因为本身已经继承了其它类,无法再继承EventDispatcher。
如果仅仅是因为这个原因,那么我更加建议使用 实现IEventDispatcher接口来进行事件发送。
但如果原因不止如此,比如,我们不愿意这个类不是一个单纯事件发送类,而是在执行某个方法(method),比如doSomething()时,附带的发送一些事件。
这些事件发送者往往是这个类的组成部分,一些更小的类,通常是Sprite等。
那么用这种做法就比较合理。
看代码例子
//以下为一个名叫KingdaSampleClass的Document Class,请自行和一个Fla绑定。package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
public class LearnCompositeEvents extends Sprite {
public function LearnCompositeEvents() {
var kingdaObj:KingdaClass = new KingdaClass();
//一定要用kingdaObj.getSender()来返回事件发送对象,才能addEventListener
kingdaObj.getSender().addEventListener(KingdaClass.ACTION, lisFunc);
kingdaObj.doSomething();
//输出:
//doSomething
//listened:yeahyeah
}
//侦听器
private function lisFunc(evtObj:Event):void {
trace ("listened:"+evtObj.type);
}
}
import flash.events.EventDispatcher;
import flash.events.Event;
class KingdaClass extends EventDispatcher {
public var _dispatcher:EventDispatcher;
public static const ACTION:String = "yeahyeah";
public function KingdaClass() {
initSender();
}
private function initSender():void {
_dispatcher = new EventDispatcher();
}
//调用一个专门的方法(method)来返回发送事件的EventDispatcher。
public function getSender():EventDispatcher {
return _dispatcher;
}
public function doSomething():void {
trace("doSomething");
//除了以下两行发送事件,还可以写入其它你要干的事儿。灵活。
var evtObj:Event = new Event(KingdaClass.ACTION);
_dispatcher.dispatchEvent(evtObj);
}
}
}
5.实现IEventDispatcher接口来进行事件发送。
在哪种情况下使用?
类可能是因为本身已经继承了其它类,无法再继承EventDispatcher。
而我们恰恰希望它能实现EventDispatcher类所有功能,比如说addEventListener, hasListener等等,看起来简直和继承EventDispatcher没什么分别。
那么OK,我建议使用 实现IEventDispatcher接口来进行事件发送。
其实质是一个装饰器模式(Decorator),以对客户端透明的方式扩展对象功能,是继承关系的一个替代方案。其关键在于扩展是完全透明的,使用起来和继承父类几乎没什么区别。
具体方法
由于IEventDispatcher需要实现5个接口,addEventListener, hasListener, willTrigger,removeEventListener,hasEventListener,那么我们的装饰类也必须实现这五个接口。
其余看代码
优点:
1.类的用户完全感觉不到差别
2.在被包装的方法中还可以加入其它自己希望加进去的动作,比如,在addEventListenr方法中可以再插入一个计数,看看到底被add了多少次,超过某些次后,调用某个方法等等。
总而言之,给我们带来了极大的灵活性。这就是装饰器模式的好处。package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.EventDispatcher;
public class LearnDecoratorEvents extends Sprite {
public function LearnDecoratorEvents() {
var kingdaObj:KingdaClass = new KingdaClass();
kingdaObj.addEventListener(KingdaClass.ACTION, lisFunc); //用起来和EventDispatcher对象一样哦,呵呵。
var evtObj:Event = new Event(KingdaClass.ACTION);
kingdaObj.dispatchEvent(evtObj);//确实一样吧 :)
//输出:listened:yeahyeah
}
private function lisFunc(evtObj:Event):void {
trace ("listened:"+evtObj.type);
}
}
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
import flash.events.Event;
class KingdaClass implements IEventDispatcher{
public var _dispatcher:EventDispatcher;
public static const ACTION:String = "yeahyeah";
public function KingdaClass() {
// other ....
initSender();
}
private function initSender():void {
_dispatcher = new EventDispatcher(this);
}
//哈哈,在实现接口时还可以乘机干点别的,比如我喜欢吧useWeakReference设为true
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void{
// do other things;
_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
public function dispatchEvent(evt:Event):Boolean{
// do other things;
return _dispatcher.dispatchEvent(evt);
}
public function hasEventListener(type:String):Boolean{
// do other things;
return _dispatcher.hasEventListener(type);
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void{
// do other things;
_dispatcher.removeEventListener(type, listener, useCapture);
}
public function willTrigger(type:String):Boolean {
// do other things;
return _dispatcher.willTrigger(type);
}
}
} -
AS3.0教程(9):强大的事件机制(5) 来源:
http://www.kingda.org/archives/kingda/2006/08/as3095.html#more
作者:黑羽(KingdaSun)
有兄弟反映,似乎AS3的事件机制有些复杂。
在我看来,编程上 “复杂”这个词一般有两种定义:实现麻烦 ,或者内容众多。
AS3中的事件机制其实现并不麻烦,逻辑更加清楚简单,因此不是“实现麻烦”这一类。
那应该指的是“内容众多”这个意思。黑羽倒觉得"内容众多"往往是褒义词,意味着API丰富,控制范围和深度大。那么一旦得其要领,即思路通畅,记忆深刻,也就不会觉得“复杂”了。
我也会尽量写的简单通俗,照顾新手。但我又要同时考虑到AS2老手们的需求,不让他们打瞌睡。所以AS初学者 看到不懂的地方可以跳过,多用用Event后,有需要再回过头看看我教程的其它部分,一定会有收获。
拿今天要讲的事件发送来说,我预计写以下内容:
1. EventDispatcher和Event的简介
2. 回顾AS2.0事件发送
3. 继承EventDispatcher进行事件发送。
4. 合成EventDispatcher进行事件发送。
5. 实现IEventDispatcher接口来进行事件发送。 与设计模式中的装饰器模式相似。
那么新手看第一,第二,第三部分已经足够应付一般应用。AS2老手们要看看第四部分。 开发大型项目的AS开发者,则第五部分必看。
1.EventDispatcher和Event的简介。
AS3中Object是万物之宗母,且生养众多,共有220多个子类。Event(事件类)和EventDispatcher(事件发送者类)就是在这一代之中。 Event和EventDispatcher是事件机制的两大主角,二者缺一不可。
Event类及其子类的功能就是提供各种具体的事件供EventDispatcher使用,不能干别的。
EventDispatcher则是要让它所有的子类都能发送事件。
那么,AS3就让所有要发送事件的类都统统继承于EventDispatcher。而需要发送事件的类毫无疑问,都是些很重要的类,比如URLLoader,DisplayObject。
其中DisplayObject更是一代霸父,所有可视对象,比如MovieClip,Spirit等等等等统统都是它的子孙。
因此,父以子贵,EventDispatcher在Object的第一代子女中,位高权重,影响极大。
2. 回顾 AS2.0中发送事件
AS2.0中发送事件是怎么干的?
在类中留几个函数对象,如 dispatchEvent:Function,再搞一个EventDispatcher.initialize()来初始化一下要发送事件的类,然后,就搞定了。.....好简单。
但AS3中更简单,更加标准。
3.继承EventDispatcher进行事件发送。
继承是最方便最快的一种。
刚刚说过了,所有的可视对象都继承DisplayObject,是EventDispatcher的孙子辈,因此都可以直接使用dispatchEvent()来发送事件了。
看代码,我们让一个普通的MovieClip, KingdaMC,来发送一个莫名其妙的事件,比如说"KingdaPlaySC"。
KingdaMC.dispatchEvent(new Event("KingdaPlaySC"));
现在我们要让一个我们自己的类来发送事件。
以下为一个名叫KingdaSampleClass的Document Class,请自行和一个Fla绑定,如果忘了怎么弄,看第三篇教程。
-------------------------------------------------
package {
import flash.display.Sprite;
import flash.events.Event;
public class KingdaSampleClass extends Sprite {
public function KingdaSampleClass() {
//生成一个KingdaSampleDispatcher的实例
var dispatcher:KingdaSampleDispatcher = new KingdaSampleDispatcher();
//标准的实现
dispatcher.addEventListener(KingdaSampleDispatcher.ACTION, actionHandler);
dispatcher.doSomething();
//可以用直接字符串标识事件类型,但推荐使用静态加const的字符串
dispatcher.addEventListener("KingdaPlaySC", anotherHandler);
//直接用new Event生成一个新的事件对象,该对象的事件类型为"KingdaPlaySC"
dispatcher.dispatchEvent(new Event("KingdaPlaySC"));
//输出:
//action的侦听器: [Event type="action" bubbles=false cancelable=false eventPhase=2]
//KingdaPlaySC的侦听器: [Event type="KingdaPlaySC" bubbles=false cancelable=false eventPhase=2]
}
private function actionHandler(event:Event):void {
trace("action的侦听器: " + event);
}
private function anotherHandler(event:Event):void {
trace("KingdaPlaySC的侦听器: " + event);
}
}
}
import flash.events.EventDispatcher;
import flash.events.Event;
class KingdaSampleDispatcher extends EventDispatcher {
public static var ACTION:String = "action";
//如果你需要在自己类中某个方法中发送事件,那么示例如下
public function doSomething():void {
//你的代码.....
//发送事件
dispatchEvent(new Event(KingdaSampleDispatcher.ACTION));
}
} -
AS3.0教程(8):强大的事件机制(4) 来源:
http://www.kingda.org/archives/kingda/2006/08/as3084.html#more
作者:黑羽(KingdaSun)
本节内容:
1.弱引用的使用原则
2.listener的不同和this关键字的指向。
继续上次的话题。在讲listener 和 this关键字之前,我们先来讲讲一个高级话题:
弱引用的使用原则。
新手可以不看,因为暂时用不到。但这个话题很有必要。当设计大型RIA应用程序时,弱引用必须要了解。
弱引用从原则上来讲,其引入是为了防止无意识的对象保留(unintentional object retention)引起的内存泄漏。
什么是无意识的对象保留?一般情况下,对象的逻辑生命周期和实际生命周期应当相同。但是在某些情况下,比如事件侦听器机制,我们可能会创建一个引用,它在内存中生存的时间比我们预期的要长很多。比如说,下面的例子中,即使删掉了侦听器lis,但事件还是能被继续捕捉。这是由于并没有removeEventListenr,那么系统中还会保留着对侦听器的引用。
如果没有把addEventListener中对侦听器的持有改成弱引用,那么这个侦听器会一直存在、耗掉内存不被人发觉。但如果设成了弱引用,那么垃圾回收器过段时间后会将侦听器占用的内存回收,此时侦听器从物理意义上才真正的被销毁了。
在销毁之前,这个侦听器还会继续存在,继续作用。这就是为什么下例中虽然已经把useWeakReference设为了true,但是还是会有作用。
那么什么时侯垃圾回收器(Garbage Collector)才会来回收呢?
唔,这要看它高兴了,快的话10分钟,慢的话一个月。哈哈,开玩笑,垃圾回收器的工作时间咋一看确实是不可测的,但也有规律可循。但这个问题探讨在本系列教程中显得过于艰深,会单独撰文来说明垃圾回收器的部分工作机制。
那么推论来了,我们凭什么要把useWeakReference设为false呢?除非我们有意要让某个侦听器在失去了其他所有引用的时候还要工作,才有可能这样做。但谁会有这样疯狂的想法呢?道哥还是包世宏?
所以,我建议,大家不妨养成习惯,把useWeakReference设为true。
当然最好的做法是始终记得不用侦听器了,一定要removeEventListener。在这一点上,我们要坚持“始乱终弃”!!
//这个是Document Class,建个fla,绑定这个class。忘了,就看第三篇教程。package
{
import flash.display.MovieClip;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
public class LearnEvents extends MovieClip
{
function LearnEvents() {
var lis:Function = function () {
trace ("听到了鼠标Click事件!");
}
var kingda_s:KingdaSprite = new KingdaSprite(0xFFCC00, "kingdaSquare");
addChild(kingda_s);
kingda_s.addEventListener(MouseEvent.CLICK, lis, false, 0, true); //瞧,最后一个参数,已经把弱引用设为true了
lis = null; //这一句,我已经从逻辑上删掉lis了,大家作证啊
trace ("侦听器还在吗?:"+ lis); //lis也确实指向null了。但你只要继续点击方块,你会发现Click事件仍然被捕捉到。
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
//这个类就是画一个矩形,
class KingdaSprite extends Sprite {
public var nickname:String;
public var ColorNum:uint;
//colorNumber就是#ffcc00这种类型的数,在AS3中推荐用新的uint型来标记它
public function KingdaSprite(colorNumber:uint, nameString:String) {
ColorNum = colorNumber;
nickname = nameString;
graphics.beginFill(ColorNum);
graphics.drawRect(0,0,100,100);
graphics.endFill();
}
}
Listener和As2.0有何不同,和this关键字的“改进了的记忆力”
DOM Level 3中规定的是用Object来做listener。该Object有用来处理事件的方法(method)。
AS3虽然是按照DOM Level 3事件机制设计的,但也不完全听话,有自己独立的想法。在AS3中,侦听器就是函数。也只能用函数来侦听。
其实在Actionscript3中,Function实质也是一种特殊的Object,和AS2.0有相似之处。
见文章:
Actionscript高级技巧:深入了解Function
因此AS3.0为什么限定用Function,这和它的架构有关,不细说了。
但有趣的是,在AS3.0中,对IEventDispatcher的定义中,仍然按照DOM3标准用Object来做Listener。见上一篇教程和随后的评论。
那么问题来了,function中this关键字的指向会怎样?
AS2.0开发者对AS2.0 事件机制中 this关键字的水性杨花应该深有认识。如果用function做侦听器,那么谁发出事件,this就指向谁。这就等于对象之间乱搞关系,啊呀呀。所以MM派了一个Delegate代理警察类来管理。唉,糜乱的岁月不堪回首啊。
//Actionscript 2.0例子:拷贝以下代码到第一帧,拖一个button到舞台,命名为kingda_btn;function lisFunc() { trace ("亲爱的,你会指向谁:"+ this.name); //我们本意应当是指向_root;}kingda_btn.addEventListener("click", lisFunc); //点一下button,看看指向谁。
回到Actionscript 3.0,来看看坚定的夫妻关系,总结为:嫁鸡随鸡,嫁狗随狗,什么都不嫁,那就属于global。我靠,读一下,还挺押韵。大家也好记。
简单的解释一下,函数在哪个对象里(应该叫method),那么this就指向谁。不在对象里,那么就指向global。
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
public class AddListener extends Sprite {
public function AddListener() {
//用package外面定义的类KingdaSprite创建一个实例,由于同文件中,所以不用import啦
var outsideChild:KingdaSprite = new KingdaSprite(0x00FF00, "outside_sprite");
addChild(outsideChild);//没有了这一句,你啥都看不到。
outsideChild.addEventListener(MouseEvent.CLICK, inclassHandler);//注册类里面的侦听器
outsideChild.addEventListener(MouseEvent.CLICK, outsideHandler);//注册类外面的侦听器
}
private function inclassHandler(event:MouseEvent):void {
trace("类里面的侦听器侦听到MouseEvent事件: " + event);
trace("this关键字指向:"+this);
}
}
}
function outsideHandler(event:MouseEvent):void {
trace("类外面的侦听器侦听到MouseEvent事件: " + event);
trace("this关键字指向:"+this);
}
import flash.display.Sprite;
import flash.events.MouseEvent;
//这个类就是画一个矩形,然后你点击这个矩形会发出标准鼠标click的事件
class KingdaSprite extends Sprite {
public var nickname:String;
public var ColorNum:uint;
//colorNumber就是#ffcc00这种类型的数,在AS3中推荐用新的uint型来标记它
public function KingdaSprite(colorNumber:uint, nameString:String) {
ColorNum = colorNumber;
nickname = nameString;
graphics.beginFill(ColorNum);
graphics.drawRect(0,0,100,100);
graphics.endFill();
}
} -
AS3.0教程(7):强大的事件机制(3) 来源:
http://www.kingda.org/archives/kingda/2006/07/as3073.html#more
作者:黑羽(KingdaSun)
(2) addEventListener语法的不同,原因,和const型必要性和用法
本例如果是AS2.0,那么代码是这样写的:outsideChild.addEventListener("click", inclassHandler);
本例是3.0,如果你trace一下其中的MouseEvent.CLICK,输出的也是字符串"click"。
看起来AddEventListener的方法和以前也没什么大的出入。和这世界上大多数相同的事物一下,表象的类似却掩盖着本质的巨大差异。
我们先从最小的差异讲起:
1.使用类静态属性,用const定义事件字符串名称变量AS3.0中用了一个新的关键字定义了事件名称字符串变量,代码是public static const CLICK:String = "click";
const,是英文constant的缩写,意思使不变的,常量。那就意思很明白了,一旦这种类型的常量被定义就不可再更改。好处通俗的说就是规范好项目,规范你自己,也规范任何其他项目人员,动不了这个变量。
你可能还是会不屑一顾,这么小的一个改动,对我没什么用!
可我的AS2.0开发血泪经验是,我曾经花了一个下午来找bug,最后却发现是某个类的addEventlistener()里面的事件名称"click"手误打成了"cilck"。编译器可不管这个。
如果是3.0,你打成了MouseEvent.CILCK,那么编译时立刻会报错提醒你,多好啊。一个项目一个人做十几个类还好办,自己认真点还能顶的住;如果是一个项目几个人几十个类,那么没有const和static的帮忙,管理事件类型还真是有点麻烦。即使实现了也没有AS3.0这么简单直观。
回到代码,我们要记住,日后我们开发自己的Event类时,也要像这样,用public static const来定义我们自己的事件名称。
如何自定义自己的事件,我会在EventDispatch那一节讲述。
看看代码,我们还发现AS3.0中侦听器也发生变化了,只能用function来做侦听器,不再用Object。
2.addEventListener高级运用AS3.0中对侦听器的改进远远不止以上这些,看一看addEventListener的实现接口:function addEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false,
priority:Integer=0,
useWeakReference:Boolean=false):Boolean;
哇塞,有三个莫名奇妙的参数。可是当你知道这三个参数背后隐藏的巨大改进之后,相信你要大叫三个哇塞。第一个神秘参数,目前暂不解释,埋个伏笔,留到EventDispatcher那一节,讲Actionscript3崭新的Event Flow事件流机制.第二个参数:优先级。 有趣吧,在Actionscript 3.0中我们可以控制事件的优先级,从而达到控制function侦听器的执行顺序。如果你不填这个参数,那么事件默认为同一个级别0,事件的执行按先来后到的天经地义的顺序。如果设为1,那么事件级别降一个档次,稍后执行。数字越高优先级越高。级别可以为负数。(注意: Flex Builder 2 Beta3中事件级别是越低越高)
好好利用这个功能吧,在AS2.0中要想达到同样效果可不知道要多费多少力气!
第三个参数,讲的是是否设为弱引用。
兄弟们初学As2.0时一定经常忘了在删除Listener对象时,却忘了removeEventListener吧。这会导致很多莫名奇妙的情况发生。也是最常见的诡异bug种类之一。即使老鸟偶尔也会被阴一把。
最郁闷的是这种情况往往不被发现,在后台默默的消耗大量资源。
现在可以用弱引用可以在某种程度上解决这种bug。
设为true,就是告诉垃圾回收器,这个侦听器function的引用是弱引用。一旦这个侦听器在运行时只剩下了这一个弱引用,那么垃圾回收器可以不理它,直接把它回收咯屁了,节省资源。
从AS3.0引入这个弱引用这个概念就可以看出,AS3.0是如何的重视资源管理和有效率的运用。一个标准的重量级的程序语言必须具有这样的特征。
现在AS3.0有了!
下一节:
(3) Listener和As2.0有何不同,和this关键字的“改进了的记忆力”




