就如人们对习以为常的东西不以为然,但真正发现与当初想的不一样时那种惊讶难以言喻。这就比如相对论的出来彻底改变了对旧世界的看法――时间不是一层不变的东西,就算在地球上,坐在飞机上人跟地面上的人时间是不同的,它们都由速度决定。有人不敢相信,有人高兴,有人认为无聊,因为没用。事实上我们根本感觉不出来差别,但我们还是要去追求,因为知识代表者力量。当某个未来需要它时,那发挥出的力量是无穷无尽的。
说了这么多切入正题吧,舞台和时间轴的真相正如相对论一样是不引起注意的,但真相带给我们的收获是巨大的。为了使得教程更加面向原因,这里采用问答形式慢慢揭开面纱。本着辩证的思想,在每个观点的背后尽量用实际的代码去求证。当然,还是按照从浅到深的顺序开始。
问:Flash中的主时间轴是舞台吗?
答:否,时间轴不是舞台。舞台是播放器。舞台可能是安装到程序中的flashPlayer.exe播放器,也可能是网页中的控件,还可以其它语言如vb,vc,中的控件。主时间轴是播放器播放的swf文件,也是常说的文档类。而舞台是Stage类。
问:什么是文档类?
答:文档类基于MovieClip。是与主时间轴绑定的类。我们可以自定义类与它绑定,如果不指定则自动生成MainTimeline类。
证明:新建一个swf,在第一帧输入:trace(this is MovieClip),向上转型成功,返回true。
问:MainTimeline做了什么事情?
答MainTimeline类自动导入了flash核心类库,以flash开头的包都被导入了。核心类库的swc文件名为:playerglobals.swc。可以在flash的安装目录下搜索到。MainTimeline还自动生成对舞台上的对象引用并初始化。
证明:我们在文档类中建立一个空类:
- package
- {
- import flash.display.Sprite;
- public class Document extends Sprite
- {
- }
- }
复制代码
然后在时间轴第一帧输入var shape:Shape=new Shape();报错,原本可以直接使用的Shape没有定义。
附:as3不建议在时间轴上写代码,因为那是脚本编程方式,但在时间轴上非常适用调试代码,因为省去了导入,构造函数等等繁琐的事情。
问:全局坐标指的主时间轴坐标还是舞台坐标?
答:指舞台坐标。
证明:在舞台上画一个方块,起名为mc。在第一帧上输入如下代码:
- mc.addEventListener(MouseEvent.CLICK,clickHandle);
- function clickHandle(evtObj:MouseEvent):void
- {
- var p:Point=new Point(evtObj.localX,evtObj.localY);
- trace(p);
- p=mc.localToGlobal(p);
- trace(p);
- trace(evtObj.stageX,evtObj.stageY);
- }
复制代码
对照可以分发现转换后的坐标就是舞台坐标。
问:主时间轴,也就是文档类的坐标跟舞台有什么不同?
答:文档类与舞台是显示列表中的两个顶级容器,舞台是文档类对象的容器。文档类的坐标相对于文档类对象,舞台坐标相对于舞台。当文档类对象和舞台原始坐标点不同时,区别就显现了。
证明:在舞台左上角画个方块,坐标为(0,0)。在第一帧输入如下代码:
x=10;
y=10;
可以看到方块位置变了。这说明文档类对象不必非要跟舞台原坐标点重合。正式因为平时都是重合的,所以看不见差别。
问:文档类大小也跟舞台大小不同吗?
答:是的。舞台是可以缩放的,当缩放舞台时可以不缩放文档对象,即使缩放文档对象也不一定拉伸到整个舞台。所以当然是不同的。
证明:如图:
问:舞台有哪些缩放方式:
答:使用Stage的scaleMode来控制缩放模式。scaleMode使用StageScaleMode类的静态常量表示:
StageScaleMode.NO_SCALE
swf文件不随播放器窗口改变。会自动居中。
StageScaleMode.SHOW_ALL
以缩放方式缩放swf文件,维持宽高比。
StageScaleMode:NO_BORDER
以裁剪方式缩放swf文件,维持宽高比。
StageScaleMode.EXACT_FIT
拉伸swf文件,改变宽高比。
注意:在调试模式下NO_SCALE是默认值。而在发布后SHOW_ALL是默认值。
附:由于可以选择缩放,我们在网页中可以使用两种方式让swf在网页中居中:
1.使用缩放模式。使用网页代码让控件居中。
2.控件随着网页的大小而改变。采用noscale模式使内容居中。
问:缩放看起来非常适合播放动画。但当制作应用程序时不必缩放,能否让swf不要自动居中?
答:可以。在NO_SCALE模式下可以使用align属性来确定对齐方式,align使用StageAlign类的静态常量表示:
StageAlign.TOP: 顶对齐
StageAlign.BOTTOM: 底对齐
StageAlign.LEFT: 左对齐
StageAlign.RIGHT: 右对齐
StageAlign.TOP_LEFT: 左上对齐
StageAlign.TOP_RIGHT: 右上对齐
StageAlign.BOTTOM_LEFT: 左下对齐。
StageAlign.BOTTOM_RIGHT: 右下对齐。
我们可以在播放器中导入多个swf采取不同的对齐方式。组合成一个应用程序。
问:舞台的大小如何访问?
答:舞台大小使用stageWidth和stageHeight访问。不管采用哪种缩放模式,都是播放器或者控件的实际大小。
问:鼠标事件中的stageX和stageY也是这样吗?
答:不是,当使用除NO_SCALE之外的模式缩放后,swf文件也被缩放了,舞台内部DPI发生了变化,stageX与stageY是新DPI下的舞台坐标。
问:舞台也继承DisplayObject,那么舞台的x,y和width,height又指的什么?
答:舞台的x,y,width,height都是只读的。由于播放器不允许我们改变在系统中的位置,所以x,y都为0。width和height属性也不是改变播放器的大小,而指向文档类的width和height。
证明:
画一个方块,在第一帧输入如下代码:
- trace(root.width==stage.width,root.height==stage.height);//结果为true,true。
复制代码
问:文档类的x,y是文档类在舞台上的坐标,那么文档类的width和height是文档类的宽和高吗?怎么root.width和root.height结果与属性面板中设置的不同啊。
答:root.width和root.height确实不是文档类的大小。属性面板中才是文档类的大小。
问:那么文档类的大小用什么来访问呢?
答:文档类的大小使用文档类的loaderInfo属性访问,是loaderInfo.width和loaderInfo.height。
问:为什么我访问时提示:Error: Error #2099: 正在加载的对象因尚未完全加载而无法提供此信息?
答:即使是文档类的loaderInfo属性也需要主swf文件加载完毕后才能访问,因此还是得在事件中访问。
证明:
在第一帧输入如下代码:
- loaderInfo.addEventListener(Event.COMPLETE,mainSwfComplete);
- function mainSwfComplete(evtObj:Event):void
- {
- trace(loaderInfo.width,loaderInfo.height);
- }
复制代码
看,现在可以访问了。不光是width和height,还有其它属性也需要这样访问。所以最好在complete或init中访问loaderInfo的属性。
问:那么文档类的width和height究竟表示什么?
答:问的好。文档类的width和height表示的是可视内容的大小。
证明,在舞台上画两条线,如图:
在帧上输入:trace(width,height)。
发现大小是这两条线确定的矩形范围。
附:假设改变文档对象的背景色,也是改变可视内容范围的背景色。在帧上添加代码:
- opaqueBackground=0xFF0000;
复制代码
结果如图:
问:那么改变文档类的width和height是改变了可视区域的大小吗?
答:不完全是。flash以播放器原点为坐标原点采取按比例延伸方式,也可以称作放射。原理如图:
这张图显示了采用放射方式使宽度扩展两倍。上面一个方块中的每一个像素的横坐标都由原位置延伸到2倍距离。得到的结果是宽度延伸了2倍,横坐标也成了原来的两倍。对于高度也是这样。改变宽度为原来的两倍等价于设置scaleX=2。实际应用中由于同时改变了大小和坐标使得我们很不习惯。所以一般我们不改变文档类对象的大小。
问:当使用了opaqueBackgoundg改变主时间轴的背景色后,能响应鼠标点击事件吗?
答:不能。不但背景色不能响应点击事件,就算画一个矢量图形,导入一张位图,文档类对象也不能捕获鼠标事件。这是因为这些图形不是InteractiveObject的子类,不支持鼠标事件,不能成为事件目标,而系统也不选择文档类对象作为事件目标。使得系统直接选择舞台为事件目标。
证明:画几个矢量,再载入一副位图,在帧上添加代码:
- addEventListener(MouseEvent.CLICK,clickHandle);
- stage.addEventListener(MouseEvent.CLICK,clickHandle);
- function clickHandle(evtObj:MouseEvent):void
- {
- trace(evtObj.currentTarget);
- }
- dispatchEvent(new MouseEvent(MouseEvent.CLICK));
复制代码
点击矢量和位图,输出的只有stage而没有主时间轴。
问:那么文档类对鼠标一点作用都不起了吗?
答:否,虽然系统不选择文档类对象作为事件目标,但文档类关于鼠标交互属性还是有作用的。这个属性就是mouseChildren。使用这个属性能够禁用swf文件中的所有鼠标事件。
证明:在舞台上分别放个按钮,输入文本,带超级链接的文本。在帧上输入:mouseChildren=false。发现按钮没了反应,文本不能输入,超级链接也没用了。
问:我看stage也有这个属性。把stage的mouseChildren设置为false岂不可以禁止包括swf文件内的所有鼠标事件?
答:确实如此。
问:stage虽然是继承而来的,但很多成员都被禁用了。因为要禁止对播放器的修改,有些成员对播放器也无意义,那么哪些成员被Stage类保留下来了呢?哪些又是新添加的成员呢?能详细说明吗?
答:
保留的方法:
1.EventDispatcher的所有方法,用于为舞台添加特属于舞台的事件。
2.保留的容器方法。
addChild
addChildAt
removeChildAt
setChildIndex
swapChildrenAt
getObjectUnderPoint
3.Stage.invalidate()方法:
触发显示对象的render事件用于延迟技术。
事件:
由于处于显示列表的顶级,Stage的事件都不冒泡,也没有默认调用方法。事件对象是Event。属性target值为Stage对象。
fullScreen
类型为flash.events.Event.FULL_SCREEN。进行全屏切换时触发。事件对象可使用fullScreen属性,全屏为true。
resize:
类型为flash.events.Event.RESIZE。.当scaleMode设置为NO_SCALE时改变swf文件尺寸时调用。用于作布局。
mouseLeave:
类型为flash.events.Event.MOUSE_LEAVE。当鼠标离开播放器窗口时触发。
属性:
保留属性:
numChildren:
舞台中swf文件的个数。
mouseChildren:
忽略所有swf文件的鼠标事件。
下面是操作播放器的属性:
focus:
指定舞台中具有键盘焦点的对象。由于只能有一个对象具有焦点。所以由舞台来处理焦点是合适的。
frameRate:
设置舞台的帧速。默认为属性面板中指定的帧速。
stageFocusRect:
是否显示焦点矩形。一般用来调试。
scaleMode:
StageScale.Mode:
StageScaleMode.NO_SCALE
swf 文件不随播放器窗口改变。会自动居中。
StageScaleMode.SHOW_ALL
以缩放方式缩放swf文件,维持宽高比。
StageScaleMode:NO_BORDER
以裁剪方式缩放swf文件,维持宽高比。
StageScaleMode.EXACT_FIT
拉伸swf文件,改变宽高比。
stageWidth和stageHeight:
舞台的宽和高。只读属性。
width和height:
可视区域的宽高。
displayState:
as3现在拥有全新的全屏概念。再不是原来的缩放方式而是全新的硬件支持。速度大幅度提高。并且可以在网页上使用全屏。但全屏设置只被设计用来看电影,输入文本和键盘事件变得无效。displayStage使用StageDisplayStage.NORMAL和StageDisplayState.FULL_SCREEN表示全屏值。使用全屏还要求flash控件属性allowFullScreen设为true。
align:
使用StageAlign类的静态属性确定对齐方式:
StageAlign.TOP: 顶对齐
StageAlign.BOTTOM 底对齐
StageAlign.LEFT 左对齐
StageAlign.RIGHT 右对齐
StageAlign.TOP_LEFT 左上对齐
StageAlign.TOP_RIGHT 右上对齐
StageAlign.BOTTOM_LEFT 左下对齐。
StageAlign.BOTTOM_RIGHT 右下对齐。
问:我对舞台的invalidate方法不太了解,延迟技术指什么?
所谓延迟就是当需要频繁调用一段重负荷代码时,为了节约cpu资源,把这段代码推迟到下一帧执行。需要使用这段代码的不直接通过调用而是使用一个方法声明请求延迟渲染,这如同把一个公共变量设置为true,当系统发现变量的改变后就重新渲染舞台。stage的invalidate方法就是声明延迟渲染的方法。
问:我看上面舞台保留的方法虽然没有DisplayObject的多,但对于添加对象已经足够,一般在什么情况下需要对舞台添加对象呢?
答:舞台可导入多个外部swf文件在同一个播放器中播放。但更有用的是从库中创建鼠标指针,对话框等显示对象。它们被放置到最上层,且不必跟文档类搅和在一起。这使得文档类的设计跟鼠标、回话窗口分开。这些对话框等组件更容易作为公共组件框架跟其它程序迅速匹配。
问:现在对舞台与主时间轴的概念已经很清晰了。这两个对象被系统创建。我们只能通过DisplayObject中提供的stage和root属性分别引用它们,可以随时访问是吧?
答:不能随时访问,只有添加到显示列表中的对象才能引用它们。因为它们作为顶级显示容器,如果在显示列表外也可以访问,那被删除的显示对象在后台依然可以影响前台显示,这样会导致混乱。
问:主时间轴和stage也有这两个属性,它们指什么?
答:主时间轴的root指主时间轴,主时间轴的stage指舞台,舞台的root和stage都指舞台。
问:还有什么限制吗?
访问舞台还与安全模型有关。不受信任的域是无法访问舞台的,因为它们获取了舞台后可以利用扫描方式盗取用户信息。
问:原来访问舞台有这么多限制啊,那访问主时间轴应该没有什么限制吧?
答:没有。MovieClip的成员都可以使用。你甚至可以把buttonMode设置成true。让整个主时间轴成为一个大按钮。
问:那我也可以使用滤镜渲染整个swf文件了吧,使用flash不能这样呢。
答:确实。但不要滥用,使用滤镜渲染主时间轴会作用于所有显示对象,也会渲染所有帧。这会消耗很多cpu资源。
证明:在舞台上绘制各种图形,文字,图片。在第一帧输入如下代码:
- var dropShadowropShadowFilter = new DropShadowFilter();
- var filtersArray:Array = new Array(dropShadow);
- this.filters = filtersArray;
复制代码
可以看到所有对象都被添加了阴影。
|