题外话:
不少兄弟问我,AS3教程咋不出了哩?其实看我博客的兄弟们应该都知道,黑羽目前的Flash RIA整体网站,接近竣工,11月即将推出。结尾工作实在太多,从十一到上周末,基本上放假都在加班。一些博客或者论坛上兄弟的问题都没有精力回复,抱歉了。
上次还在5d上看到版主鼓动大家给我打气,让我继续,真是非常不好意思。
这个周末偶得空闲,遂集中精力,将自己开发笔记整理了一篇放上来。项目发布后,更新会正常。
![]()
彻底了解AS3视觉元件架构
DisplayObject,直译为视觉对象,意为可以被看到的对象。
视觉是Flash 成功的主要基石。当我赏析ActionScript 3 的所有视觉元件类型和其整体构架时,感到非常满意。可以看出,这次整体的架构设计是深思熟虑的结果。与其他语言,比如C#,相比有自己强烈的特色,是对Flash视觉行为贴身定做的结果。
ActionScript 3的架构乍一看很复杂,不包括UIComponent的子类,就有7到8个层,20多个莫名奇妙的类。头疼!但实际上,它的设计是非常的简洁优雅,远远比ActionScript 2一个MovieClip打天下强太多了。实际上,只要真正弄清了它的设计思路,就可以高屋建瓴,一览无余,会发现这个架构逻辑清晰,非常的易懂易记。所以,先抛开ActionScript 3 的帮助文件,我们一起来看看为什么要设计这样一个架构,搞出20多个怪胎出来。
(如蒙转载,请留下我的Blog链接:www.kingda.org, thx)
先来追忆一把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模式。所有的DisplayContainer属于Composite模式中的树枝,非DisplayContainer部分的都是树叶。树枝中都有相应的聚集对象。
另外要指出的是,MovieClip和Sprite再也不像以前2.0的MovieClip一样,对内部的不同子对象给出包装接口。比如Shape下的Graphic对象,Sprite下面的SoundTransform对象,Loader下的LoaderInfo对象,等等等等。我本来迷惑,为何不用装饰器模式,让这些元件的行为和ActionScript 2更加相似一些,过渡的痛苦少一些,但转念一想明白了架构设计师的苦心。就是要用这样清清楚楚,明明白白的Composite来加强所有开发者OOD时分工协作,更加快的熟悉和运用新的强大的架构。与这个优点相比,这么一点过渡的痛苦又算得了什么呢?
关于ActionScript 3视觉编程后续部分和具体的编程例子,会陆续放出。
(11月份更新:才发现在拷贝Word文档到博客,并编辑内容时,不小心在最后一段遗漏了几行字,现在加上。请转载的网站也加以更新,不然恐有歧义,读者难以理解。)
P.S:本教程受Creative Commons License.协议保护,未经作者同意,不得用于商业用途。







Comments (33)
豁然开朗 ^_^
感谢黑羽百忙之中抽出时间写教程
期待后续
Posted by eidiot | November 5, 2006 8:02 AM
Posted on November 5, 2006 08:02
看了兄台N个教程了,于情于理于公于私..俺也要顶下的~3Q
Posted by 东写西读 | November 5, 2006 2:03 PM
Posted on November 5, 2006 14:03
开始学as3了,一直在拜读黑羽你的教程.知道你前段时间在忙工作,今天看到这么好的文章,感动一下!怎么你就能学得这么深刻,能否透露下途径.
Posted by raytrace | November 5, 2006 4:55 PM
Posted on November 5, 2006 16:55
呵呵,从我看来
对用AS2进行RIA开发的痛苦感受越深,对AS3的理解就会越深刻!
:P
Posted by 黑羽 | November 5, 2006 7:17 PM
Posted on November 5, 2006 19:17
看来我是不用再经历as2的痛苦经验了,期待flash9的正式到来。祝黑羽的项目成功。同城的flasher。
Posted by raytrace | November 5, 2006 10:32 PM
Posted on November 5, 2006 22:32
to raytrace:
谢谢了。我住在文三。 ^_^
Posted by 黑羽 | November 6, 2006 8:58 PM
Posted on November 6, 2006 20:58
你好黑羽,看过你得一篇关于flash 9 的处理double click的文章。我现在想做的功能是:双击一个图片,使图片放大一定的倍数,放大两次之后不再放大,我在你讲的方法: kingda_mc.doubleClickEnabled = true;
kingda_mc.addEventListener(MouseEvent.DOUBLE_CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
trace("哈哈,你双击我了");
},我将function clickHandler(event:MouseEvent):void {
trace("哈哈,你双击我了");
},修改成为: function clickHandler(event:MouseEvent):void {
kingda_mc._xscale=kingda_mc._xscale*1.2;
},在flash9中调试错误,想知道原因,另外,希望你能给我些实现的思路。
Posted by jerry chen | November 7, 2006 3:29 PM
Posted on November 7, 2006 15:29
我的gmail是 jerry.chen.ch@gmail.com,
公司邮箱是: jerry.chen@coresolutions.com
可以坦白的说,我对flash不是很熟悉,值是看了几天而已,之前要求的是通过放大镜按钮来放大,缩小,还原图片,那个我已经做好,现在改成鼠标双击放大,查了半天发现flash9以下不支持对movie clip实例添加侦听,想请教你在flash9中如何实现。want to get your answer and solutions as soon as possible.Thanks and regards.
Posted by jerry chen | November 7, 2006 3:36 PM
Posted on November 7, 2006 15:36
to jerry chen:
AS3中再也没有公开的带有下划线的属性了
所以你这句
kingda_mc._xscale=kingda_mc._xscale*1.2;
肯定错误,这是AS2的MC属性
AS3中改成如下一句即可:
kingda_mc.scaleX *= 1.2;
至于侦听,你大概没有看我关于AS3 Event系列教程,所有视觉元件在AS3中都可以发送事件了。
Posted by 黑羽 | November 8, 2006 2:57 PM
Posted on November 8, 2006 14:57
KingDa你QQ多少,加一个我,有事相商:459526383
Posted by zas | November 8, 2006 3:39 PM
Posted on November 8, 2006 15:39
hi, zas
QQ已加
Posted by 黑羽 | November 9, 2006 1:06 AM
Posted on November 9, 2006 01:06
感谢黑羽的as3系列文章,我也正在学习as3,虽然平时看document比较多,但你的文章给我信心,我知道当我不懂时,总有一个地方可以给我答案!
我在杭州市滨江区,:)
qq:151952789
msn:tangyifei830217@hotmail.com
很想和你交个朋友!
Posted by 剑走偏锋 | November 10, 2006 11:13 AM
Posted on November 10, 2006 11:13
黑羽:看到你的教程感触很大,很想和你更深一步交流学习,
我的QQ:179459188
Posted by 落花 | November 13, 2006 4:58 PM
Posted on November 13, 2006 16:58
期待你的新文章
Posted by dnha | November 22, 2006 2:55 PM
Posted on November 22, 2006 14:55
做得好!!
Posted by haihai | November 25, 2006 11:00 AM
Posted on November 25, 2006 11:00
to 剑走偏锋:
hi,你好。
我的msn和qq现在已经快爆了,不准备再加人了。sorry,见谅。
如果有问题,可以到blueidea的flash版找我,或者在博客留言。我有时间,会尽量回复的。 ^_^
Posted by 黑羽 | December 3, 2006 5:19 PM
Posted on December 3, 2006 17:19
写得真好啊!受教了。。
Posted by Dstart | December 8, 2006 10:21 AM
Posted on December 8, 2006 10:21
老大,休息够了,继续发呀.
兄弟们等急了
Posted by heimuxiao | December 8, 2006 3:26 PM
Posted on December 8, 2006 15:26
呵呵很精彩,期待继续受教~感觉以后flash开发的门槛便得很高了,应该是分工明确了吧~
Posted by wonder | December 14, 2006 4:19 PM
Posted on December 14, 2006 16:19
现在一搜AS3的教程,都是黑羽的,向你学习!
Posted by Adam | December 22, 2006 7:30 PM
Posted on December 22, 2006 19:30
我住文二路,哈哈。。。。。。。
Posted by musicdance | January 15, 2007 2:05 PM
Posted on January 15, 2007 14:05
真是 太有才了 o >_ o >_ o >_ o >_
黑羽大哥一定以后要多向你学习!
Posted by HUPEIKANG1 | February 21, 2007 10:22 PM
Posted on February 21, 2007 22:22
o >_
Posted by HUPEIKANG1 | February 21, 2007 10:26 PM
Posted on February 21, 2007 22:26
请问能不能再讲清楚一点
Loader 和 URLRequest
还有 Preloader Stage
?这些 还是不大懂。
跟AS 2比,变化真是太大了!
现在 貌似 在flash方面没有常识了。。。全部要重新来了。。架构都变了。。
谢谢了~
Posted by HUPEIKANG1 | February 21, 2007 10:38 PM
Posted on February 21, 2007 22:38
黑哥。从来都没接触过AS,从那学起?
Posted by li | February 26, 2007 6:53 PM
Posted on February 26, 2007 18:53
to HUPEIKANG1:
好的,你说的这些内容我有空时再写上。
^_^
to Li:
从ActionScript3学起。它比AS1,AS2都规范,更简洁且有逻辑性,所以最好学。
Posted by 黑羽 | February 27, 2007 4:33 PM
Posted on February 27, 2007 16:33
看完了。。
说声谢谢。。
Posted by 小章 | April 5, 2007 11:32 PM
Posted on April 5, 2007 23:32
学习~
多指教Q:309954667
Posted by _lby | May 20, 2007 12:56 AM
Posted on May 20, 2007 00:56
原来是同城的,我也在文三,有机会真要拜见一下高人!
Posted by cranne | May 25, 2007 10:02 AM
Posted on May 25, 2007 10:02
黑羽你的文采非常好,技术也相当不错,简直文武俱全啊,我也是杭州的,在教工路西湖数源软件园上班,能否加你QQ,我的是46211256
Posted by eric | June 7, 2007 2:32 PM
Posted on June 7, 2007 14:32
to eric
hi,你好。
我在浙大国家科技园。我的QQ目前快爆了,不好再加人了。见谅。:)
有事儿,你可以发信到我的gmail中。
Posted by 黑羽 | June 11, 2007 10:08 AM
Posted on June 11, 2007 10:08
羽哥:看了你的一系列教程,真是受益颇多,顶一下~~,希望这样的教程继续下去.
提个建议:要是有时间的话,讲一些游戏开发之类的就更好啦.呵呵.^ ^
Posted by fireice | June 11, 2007 12:29 PM
Posted on June 11, 2007 12:29
配张图示就更好了
Posted by guest | August 24, 2007 8:31 PM
Posted on August 24, 2007 20:31