这本开源书假设读者已经有 ActionScript 3.0 的开发经验,或者学过并有一定的基础,如果没有,那请先找一本基础的 AcrionScript 3.0 先学习一下,再回来阅读本书将会有更好的效果。
本章内容将会一起研究一些 AS3 中一些重要的知识点,也是展示 AS3 特性的知识。
ActionScript 3.0 和 Flash Player 9 的渲染模型已经和以前的版本有很大不同。以前 MovieClip是渲染的焦点。swf 电影的根节点就是 MovieClip (现在用Stage). 根节点MovieClip 可以包含子节点 MovieClips, 子节点还可包含更多的子节点MovieClips。这样的层次结构用来控制MovieClips 的绘制(深度越深表示显示在最顶层) 。createEmptyMovieClip( ), attachMovie( ), 或duplicateMovie- Clip( ) 用来创建MovieClips。一旦MovieClip 被创建,它就自动添加到这个可视化层级列表中通过渲染器进行绘制。MovieClips 在层级列表中不能移动位置,非要这么做则只有删除当前的,然后在指定位置创建。
新的渲染器仍基于层级结构,但是于之前相比是经过最优化处理,更简单和灵活。新的渲染模型类都集中在 flash.display 包中。这个包中包含所有在.swf 电影中用到的可视化类。其他不在该包中的任何对象都不会被渲染器绘制。每个.swf 电影包含一个可视化对象列表,有下面三种类型:
-
stage
stage 是可视化对象列表层级的根节点。每个电影有一个stage 对象,它包含屏幕上显示出的所有对象。实际上stage 是一个容器,可以通过引用stage属性来访问任何可视化对象。 -
可视化对象容器
可视化对象容器包含其他可视化对象, stage 就是个可视化对象容器。其他的可视化对象容器包括 Sprite, MovieClip, 和 Shape。当一个可视化对象容器被删除时,它包含的所有子对象都将被删除。 -
可视化对象
可视化对象就是一个可显示的元素。有两种一种是可视化对象容器,比如MovieClip,另外是可视化对象,比如一个TextField。可视化对象创建后不会立即被显示出来,只有被添加到可视化对象容器后才被显示。
使用DisplayObectContainer类的addChild( ) 和addChildAt( ) 方法 使用DisplayObectContainer类的removeChild( )和removeChildAt( )方法 使用DisplayObectContainer类的setChildIndex( ) 方法改变项目的位置,getChildIndex( ) 和 getChildAt( ) 方法得到项目在显示列表中的位置,getChildByName()可根据实例名称获取对象。
使用各种鼠标事件监听鼠标动作,并作出反应。使用DisplayObject 实例的只读属性mouseX 和mouseY检查鼠标相对位置,或者MouseEvent事件的localX 和localY 属性。
需要使用特殊的InteractiveObject 可视化对象,它提供了响应用户鼠标的能力。如果回过头来看那张可视化对象层级图,你会发现InteractiveObject 类处在很高的层上,那些Sprite, Loader, TextField, 和MovieClip 类都在它的下面。 InteractiveObject 实例发出必要的鼠标事件,下面是些常用的鼠标事件:
- click 当用户在显示的物体上单击鼠标时触发
- doubleClick 当用户在显示物体上双击鼠标时触发
- mouseDown 当用户在显示物体上按下鼠标键时触发
- mouseUp 当用户松开鼠标时触发
- mouseOver 当用户移动鼠标到物体上时触发
- mouseMove 当用户在物体上移动鼠标触发
- mouseOut 当用户移动鼠标离开物体时触发
- mouseWheel 当用户在物体上使用鼠标滚轮时触发
使用InteractiveObject的addEventListener( ) 方法注册鼠标事件并定义MouseEvent事件处理函数。
使用 Sprite 的 startDrop( ), stopDrag( ) 和 dropTarget 实现拖拽效果。
建拖动效果并不是想象的那么困难。Sprite 类包括了这些拖动的方法,分别是startDrag( ) 和 stopDrag( )。startDrag( ) 方法可在任何Sprite 实例上调用,要想停止拖动则调用stopDrag( ) 方法,如果拖动完成,可以检查Sprite的dropTarget 属性是否是目标位置。不需要指定任何参数就可调用startDrag( ),但实际上该方法有两个参数:
- lockCente
当为TRue 时Sprite的中心被鼠标位置锁定,不管鼠标是否按下。当为false 时只有鼠标点击它时Sprite 才会跟着移动,默认为false。 - bounds
一个矩形范围来约束拖动,被拖动Sprite是不能超出这个范围,默认为null,意味着没有约束。
AS3.0的类继承设计是深思熟虑的,所有的可视对象所属类都是DisplayObject的子类, DisplayObject又是EventDispatcher的子类,因此它们就都可以派发Event(事件)了。
useCapture:Boolean(default = false)确定侦听器是运行于捕获阶段、目标阶段还是冒泡阶段。 如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段处理事件。 如果 useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。
当事件发生后生成一个携带数据的对象,然后检查目标对象是否存在显示层中,并遍历从根容器一直到目标对象所在位置的所有对象,以树形势表示。自动检测所经过的节点是否注册了监听器。
- 捕获阶段:捕获事件 capturing,从根节点开始顺序而下,检测每个节点是否注册了监听器。同时,Flex 将事件对象的currentTarget 值改为当前正在检测的对象。如果注册了监听器,则调用监听函数。
- 目标阶段:检测目标的监听器 targeting:触发在目标对象本身注册的监听程序
- 冒泡阶段:事件冒泡 bubbling:从目标节点到根节点,检测每个节点是否注册了监听器,如果有,则调用监听函数。
每个事件对象都有以下属性:
- target:派发事件的目标对象
- currentTarget:事件流当前正经过的目标对象
- bubbles:是否打开了冒泡功能
- eventPhase:事件流当前的阶段,1:捕获,2:目标,3:冒泡
EventDispatcher 是派发事件的武器,经它派发的事件对象必须是Event类型或者Event的子类。
Event对象中包含目标对象存放的数据,这些数据都成为Event的属性,以供侦听器使用:
Event的属性:
- bubbles:只读,布尔,事件是否开启冒泡功能
- cancelable:只读,布尔,处理事件的默认行为是否可以停止。主要针对一些系统事件,如果值为true,则Event的preventDefault方法可以使用,否则不可用。
- currentTarget:只读,对象,当前正在调用监听器的对象
- eventPhase:只读,整数,返回事件流正经历的阶段。1:捕获,2:目标,3:冒泡
- target:只读,派发事件的目标对象
- type:只读,字符,事件类型。比如鼠标点击事件的类型:click,并被定义为常量:MouseEvent.CLICK
构造函数:
Event(
type:String, 事件类型
bubbles:Boolean = false, 是否冒泡
cancelable:Boolean = false 是否可以停止
)
Event 的方法:
- isDefaultPrevented:判断preventDefault 是否已经被调用
- preventDefault:停止事件的默认行为。针对一些系统事件,* cancelable为true时才可用。
- stopImmediatePropagation:停止当前的事件流传播,包括当前正在处理的对象
- stopPropagation:停止当前的事件流传播,但不会停止当前正在处理的对象
要侦听一个事件,首先要创建一个函数来作为事件处理器,然后将这个函数注册给相应的时间类型。
this.addEventListener(KeyboardEvent.KEY_DOWN,keyHandler);
注册键盘按下事件,交给keyHandler处理。
注册了事件监听器,使用完毕后,必须使用removeEcentListener 方法删除监听函数:
removeEcentListener(
type:String, 事件类型
listener:Function, 监听函数
useCapture:Boolean = false 是否开启捕获功能,如果注册时打开,移除也要打开。
)
这里简单介绍一下 Robert Penner 的 AS3 Signals是什么,以及如何使用它让对象间的沟通更快速。它可以避免你使用常规的ActionScript事件机制,用到的代码量更少。
什么是AS3 Signals?
Signals是一个AS3事件的新的机制,灵感来自于C#的事件和Qt中的signals / slots。Signals是一种轻量级并且是强制类型的AS3通信工具。Signals 是某种程度上可以替代AS3内置事件的框架。它在API里整合了结合C#优异的signals思想和功能性的事件思想为一体。它比内置的事件更为快速,也少了很多呆板的代码。更难能可贵的是,它里面同样可以使用内置的事件,而且是内置事件运行速度的4倍。
什么是Signal?
一个Signal其本质上是一个微型的针对某个事件的特定的派发者,附带它本身的监听者数组。
一个Signal的基本概念就是,不会使用类似内置事件那种方式、基于字符串的频道,而是化为一个类中具体的event/signal成员。这意味着我们这些开发者,在对象之间如何连接和沟通等方面,有了更多的控制。我们不再需要字符串变量来代表我们的Signals。Signals能够表达为真正的对象。
如果你已经是一个ActionScript开发者,有时候在你的项目里创建自定义的事件子类时就会相当痛苦。定义常量,定义事件等等。添加监听者,移除监听者,并总是在你的派发类里继承 EventDispatcher 。你将会发现Signals会在很短时间使这一切变得轻松自如。
创建Signal和派发消息:
var sig:Signal = new Sigal(String, int, Object, Array)
sig.dispatch("Hey, Jude", 100, {name:"Andy"}, ["cake", "bike"])
可以传递任何类型和任何数量的参数
监听消息并回调处理:
sig.add(callback)
function callback():void {...}
只捕捉一次:
sig.addOnce(callback)
function callback():void {…}
更加详细的用法,请到官方了解。AS3 Signals on GitHub
有时候,你可能要区分一个按钮的单击事件和双击事件,而且需要单独响应其中一个,例如,在游戏中的包裹操作,如果你想单击的时候只想弹出菜单让玩家选择操作项,双击的时候只想使用物品,但是 AS3 中的双击时必须有单击的操作的,所以需要一点 hack 一下:
var timer:Timer = new Timer(100,1);
private function clickHandler(event:MouseEvent):void
{
timer.addEventListener(TimerEvent.TIMER, singleClickHandler);
timer.start();
}
private function doubleClickHandler(event:MouseEvent):void
{
timer.stop();
...
}
private function singleClickHandler(event:TimerEvent):void
{
}
使用定时器,上面的定时器设定了100毫秒后,发生双击事件,就停止定时器,执行单击操作,否则,执行双击操作。
As3提供了双击事件的调用,但有时候碰到双击事件无法响应,我们来研究一些原因。
官方是这样描述双击事件的:
如果 InteractiveObject 的 doubleClickEnabled 标志设置为 true,当用户在该对象上快速连续按下两次并释放指针设备的主按钮时调度。要使 doubleClick 事件发生,它必在以下一系列事件后面:mouseDown、mouseUp、click、mouseDown、mouseUp。 所有这些事件必须共享与 doubleClick 事件相同的目标。
当在一个显示对象上监听了双击事件,而且也设置了 doubleClickEnabled 为 true,如果显示对象没有子对象的话,一切都很正常,你可以相应到双击事件。如果显示对象是一个容器,而且包含有可以接受事件的子对象,那们就会出现响应不到双击事件的情况,那么可以设置对象的属性 mouseChildren = false,禁止子对象接受鼠标事件,那就可以响应双击事件了。
如果你需要子对象也要接受事件响应,那么把所有容器子对象的属性 doubleClickEnabled = true。
在ActionScript中,Shape, Sprite, Button, 和MovieClip每个类都有个graphics 属性,它是flash.display.Graphics 类实例。Graphics 类定义了一些绘图内容的API。这里讨论的基本上是如何使用Graphics类的部分API。因为Shape, Sprite, Button, 和MovieClip 类已经定义了graphics 属性,它就是Graphics实例的引用,所以没有必要再构造新的Graphics 对象。对象的graphics 属性可在对象内绘图。
sampleSprite.graphics.lineStyle();
lineStyle( )方法接受多个参数,所以得参数都是可选的,他们都是: thickness 定义线条的宽度,默认值为1,范围为0到255。如果指定的值超出它会自动工调整最接近的合法数值。
color
线条的颜色,默认为0x000000。
alpha
线条的透明度,范围为0到1,默认为1。
pixelHinting
布尔型,指示线条是否包住整个像素,默认为false。
scaleMode
flash.display.LineScaleMode 中 的 一 个 常 量 , 有 NORMAL ( 默 认 ), NONE, VERTICAL, 和HORIZONTAL。当值为NORMAL,随着所在对象的缩放而缩放。比如,如果有个含有1像素的线条的sprite被缩放到200%,那么线条的宽度也缩放到2个像素。如果设置为NONE,线条不会被缩放。如果设置为VERTICAL,则只在垂直方向所放,如果设为HORIZONTAL,则在水平方向所放。
caps
指定线条末端的封盖,它是flash.display.CapsStyle 的常量,有NONE, ROUND (默认),和
SQUARE.
joints
当连接线段时所指定的类型, 它是flash.display.JointStyle 的常量, 有BEVEL, MITER, 和ROUND(默认).
miterLimit
当连接类型为MITER 时还要指定斜接限制。默认为3,范围从1到255。
所以的参数都是可选的,可以在任何需要的时候设置lineStyle( )方法,比如说,你设置20像素画了绿线,再设置10像素画蓝线。如果调用了 clear( )方法后必须重新设置线条样式,不然就是 undefined 状态。
// 从当前到(100,100) 画一条直线
sampleSprite.graphics.lineTo(100, 100);
当ActionScript 方法一调用,现实对象所关联的Graphics 对象就会画出相应的图形,比如上面的直线由sampleSprite所关联的Graphics画出。lineTo( )把笔刷当前位置作为起点, 类似的还有curveTo( ), 或moveTo( ) 方法。 默认笔刷的起始坐标为(0,0)。moveTo( ) 方法不会画出东西,它直接把笔刷移动到目标位置。
设置好了线条样式后,就可以使用curveTo( ) 方法画曲线了。curveTo( ) 方法画出接近于贝塞尔曲线(虽然是经过性能优化) ,它需要3点,开始点,控制点和目标点:
- 开始点一般是笔刷的当前位置。
- 指定曲线的目标终点。
- 控制点决定曲线的形状,它是根据起始点和目标点的切线计算出的。如果不指定控制点画出的就是直线
curveTo( )方法需要四个参数。前两个指定控制点的x,y坐标,后面两个指定目标点的x,y坐标,下面的例子画出了控制点在0,100 和目标点在100,100的曲线:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.curveTo(0, 100, 100, 100);
使用 Graphics.drawRect( ) 方 法 画 出 直 角 矩 形 , Graphics.drawRoundRect( ) 或 Graphics.drawRoundRectComplex()方法画出圆角矩形。使用Graphics.drawRect( )方法就简单多了,直接可以画出标准的矩形。
该方法需要四个参数:
左上角的x,y坐标和右下角的x,y坐标。下面的代码画了一个100x50 的矩形,左上角为0,0:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.drawRect(0, 0, 100, 50);
Graphics.drawRoundRect( )方法可画出圆角矩形,只不过后面多了个参数圆角半径,看下面的例子:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.drawRoundRect(0, 0, 100, 50, 20);
Graphics.drawRoundRectComplex()基本上和drawRoundRect( )一样,只不过它可以指定每个圆角的半径:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.drawRectComplex(0, 0, 100, 50, 0, 20, 5, 25);
sampleSprite.graphics.endFill();
Graphics类有个drawCircle( )方法可以简单的画出圆,drawCircle( )参数如下:
- x 圆中心的x坐标
- y 圆中心的y坐标
- radius 圆半径
下面画出了中心点在100,100,半径为50的圆:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.drawCircle(100, 100, 50);
也可用beginFill( ), beginGradientFill( ), 或beginBitmapFill( ) 填充圆,以endFill( )结束:
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.beginFill(0xFF0000);
sampleSprite.graphics.drawCircle(100, 100, 50);
sampleSprite.graphics.endFill();
使用Graphics.beginFill( )和Graphics.endFill( )方法对完成图形填充要填充图形, 在画图形之前必须前调用beginFill( )方法, 画好图形后调用endFill( )方法结束填充 。你不能填充已经画好的图形,在填充图形之前必须前记得先调用beginFill( )方法。 MovieClip.beginFill( )方法接受两个参数:
- fillColor 指定RGB值作为填充色
- alpha 值范围在0到1之间,用于控制透明度,默认为1。
要想创建透明的填充图形,alpha值小于1就行,如果alpha为0,就不会填充图形了。 endFill( )方法不需要参数,它指示以 beginFill( ), beginGradientFill( ), 或 beginBitmapFill( ).开始的填充完成。
Graphics.beginBitmapFill()方法允许用位图填充图形,它接受以下参数:
- bitmap 填充用的BitmapData对象 matrix 默认下不需要应用转换,也可指定flash.geom.Matrix对象进行位图的缩放,旋转,倾斜,透明等变换。
- repeat 布尔值,指定是否平铺位图,默认为true。
- smooth 布尔值,指示对位图进行光滑处理,默认为false。
代码:
package {
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.BitmapData;
import flash.events.Event;
public class Drawing extends Sprite {
private var _loader:Loader;
public function Drawing() {
_loader = new Loader();
_loader.load(new URLRequest("http://www.rightactionscript.com/samplefiles/image2.jpg"));
_loader.contentLoaderInfo.addEventListener(Event.COMPELTE,onImageLoad);
}
private function onImageLoad(event:Event):void {
var bitmap:BitmapData = new BitmapData(_loader.width, _loader.height);
bitmap.draw(_loader, new Matrix());
var matrix:Matrix = new Matrix();
matrix.scale(.1, .1);
var sampleSprite:Sprite = new Sprite();
sampleSprite.graphics.lineStyle();
sampleSprite.graphics.beginBitmapFill(bitmap, matrix);
sampleSprite.graphics.drawCircle(100, 100, 100);
sampleSprite.graphics.endFill();
addChild(sampleSprite);
}
}
}
使用DisplayObject.mask 来设置遮罩,遮罩可用来创建唯一的图形或视觉效果。例如,可以创建擦除和过渡效果。还可以创建有趣的动画效果,甚至是图形扭曲效果。任何可视化对象都可以作为任一对象的遮罩,下面的代码把 sampleSprite的遮罩设置为maskSprite: sampleSprite.mask = maskSprite;
和Flash 8 中的BitmapData类一样,这是非常重要的一个类,起初,Flash只是基于矢量的一个工具,矢量图形是由数学方法描述图形元素,比如一条直线是从x0, y0 扩展到x1, y1。 而一个位图,它把图形描述为一个矩形区域值集合,每个点都对应一个颜色值。矢量图有两大优势:缩放和文件大小。当你缩放矢量图时,图像总能保持清晰,而位图当放大时就会出现锯齿状变得不清晰。
正因为矢量图是一个线条,曲线和图形的坐标组成的列表,所以它的文件和位图相比小很多。而位图要记录每个点的颜色值,信息量非常大,也就导致了文件的庞大。矢量图的这种优势使它作为Flash媒体格式的最好形式,但是位图也有它自己的优点,比如位图能很好的表现照片,如果用矢量图去描述照片的所有颜色和图形,那结果就是比位图的文件还要大了。
位图另一个好处就是很容易进行处理,矢量图的每个曲线都是经过计算出来的,如果图像复杂就会花很长时间去处理,而位图就容易处理多了,无论多么复杂的动画,位图总能表现的很好。Flash 8 对位图的支持还是很有限的, 虽然能够载入位图显示, 但不能作过多的处理。 BitmapData类提供了很好的方法来操作位图。
使用BitmapData类构造一个新的BitmapData对象 BitmapData类表示一个由象素组成的位图,包含了很多内建的方法控制和处理图像。第一步先创建该类实例: var bitmap:BitmapData = new BitmapData(width, height,transparent, fillColor); 创建出 BitmapData 实例后就存在于内存中了,虽然现在就可以创建内容,不过在没加入到显示列表中之前它是不显示的。
使用BitmapData 创建位图,并加入到可视化对象列表。 在ActionScript 3.0里要让对象可视,则必须加入到可视化对象列表中才行,然而addChild( ) 方法添加的对象必须是flash.display.DisplayObject的子类才行,而BitmapData 类继承自Object,所以不能直接加到列表中。要加到可视化对象列表中,可使用flash.display.Bitmap类,它是DisplayObject.类的子类,实际上是BitmapData的一个包装类,允许BitmapData可被显示。 当用Bitmap构造函数创建实例时把BitmapData引用作为参数传递给它,然后调用addChild( )把Bitmap 加入到显示列表,下面的例子创建了红色背景的BitmapData :
var bitmap:BitmapData = new BitmapData(100, 100, true, 0xffff0000);
var image:Bitmap = new Bitmap(bitmap);
addChild(image);
用BitmapData类的draw( )方法绘制内容 BitmapData 类有一些基本绘图方法,比如设置象素颜色,创建填充的矩形,或噪波函数,但是没有基本的函数如画直线,曲线等等,为了解决这问题,可以先在movie clip或sprite画好,在把对象画到位图上去。
var bitmap:BitmapData = new BitmapData(100, 100,true, 0x00ffffff);
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xff0000, 100);
sprite.graphics.drawEllipse(0, 25, 100, 50);
sprite.graphics.endFill();
bitmap.draw(sprite);
使用BitmapData类的getPixel( ), setPixel( ), getPixel32( ),和setPixel32( ) 方法
使用BitmapData类的fillRect( )方法
BitmapData 类没有提供绘图方法,只有些填充方法,使用起来也是很简单的,只要传递一个矩形和颜色就可以了: _bitmap.fillRect(rectangle, color);
使用BitmapData的copyPixels( )方法
copyPixels( )方法的实现也很简单, 只要得到象素值然后画到其他地方, 非常类似于draw( )方法 。但是copyPixels( )可控制拷贝象素的数量和目标。只要指定一个矩形区域和目标点即可: bitmap.copyPixels(sourceBmp, srcRect, destPoint); sourceBmp是源的BitmapData,srcRect是flash.geom.Rectangle类实例,destPoint是flash.geom.Point类实例,它指定拷贝到目标位图的具体x,y坐标位置。
Loader 类可用于加载 SWF 文件或图像(JPG、PNG 或 GIF)文件。 使用 load() 方法来启动加载。被加载的显示对象将作为 Loader 对象的子级添加。因为loader是继承与容器类的,所以首先它是个容器,而URLLoader 是继承与EventDispatcher,它不是容器。
URLLoader 类以文本、二进制数据或 URL 编码变量的形式从 URL 下载数据。 在下载文本文件、XML 或其它用于动态数据驱动应用程序的信息时,它很有用。
URLLoader 对象会先从 URL 中下载所有数据,然后才将数据用于 ActionScript。 它会发出有关下载进度的通知,通过 bytesLoaded 和bytesTotal 属性以及已调度的事件,可以监视下载进度。在加载非常大的视频文件(如 FLV 的视频文件)时,可能会出现内存不足错误。
URLStream 类提供对下载 URL 的低级访问。 数据一下载,便可随即为应用程序使用,这和使用 URLLoader 时需要等到整个文件下载完不同。并且 URLStream 类还允许在完成下载前关闭流。 已下载文件的内容将作为原始二进制数据提供。 在 URLStream 中的读取操作是非阻塞模式的。这意味着您在读取数据之前必须使用 bytesAvailable 属性来确定是否能够获得足够的数据。 如果不能获得足够的数据,将引发 EOFError 异常。 在默认情况下,所有二进制数据都是以 Big-endian 格式编码的,并且最高位字节于第一位。
URLoader用于加载外部文本数据(txt/xml)和二进制数据,也能加载SWF/JPG/PNG/GIF等文件,只是通过二进制加载,然后使用Loader.loadBytes(URLLoader.data)读取。 加载图片的例子:
var req:URLResquest = new URLResquest("10001.jpg");
req.method = URLResquestMethod.POST;
var urlLoader:URLLoader = new URLLoader;
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onUrlComplete);
urlLoader.load(req);
private function onUrlComplete(event:Event):void
{
var byteArray:ByteArray = event.currentTarget.data;
var loader:Loader = new Loader;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.loadBytes(byteArray);
}
private function onComplete(event:Event):void
{
// add the picture to stage
}
加载文本的例子:
var loader:URLLoader = new URLLoader();
configureListeners(loader);
var request:URLRequest = new URLRequest("urlLoaderExample.txt");
try {
loader.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, completeHandler);
dispatcher.addEventListener(Event.OPEN, openHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private function completeHandler(event:Event):void {
var loader:URLLoader = URLLoader(event.target);
trace("completeHandler: " + loader.data);
var vars:URLVariables = new URLVariables(loader.data);
trace("The answer is " + vars.answer);
}
private function openHandler(event:Event):void {
trace("openHandler: " + event);
}
private function progressHandler(event:ProgressEvent):void {
trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatusHandler: " + event);
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
在使用Loader来加载数据时,添加侦听事件时,注意一定要给Loader的 contentLoaderInfo属性增加事件,而不是给Loader对象增加事件。
var loader:Loader = new Loader();
configureListeners(loader.contentLoaderInfo);
loader.addEventListener(MouseEvent.CLICK, clickHandler);
var request:URLRequest = new URLRequest(url);
loader.load(request);
addChild(loader);
private function configureListeners(dispatcher:IEventDispatcher):void
{
dispatcher.addEventListener(Event.COMPLETE, completeHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.addEventListener(Event.INIT, initHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
dispatcher.addEventListener(Event.OPEN, openHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(Event.UNLOAD, unLoadHandler);
}
private function completeHandler(event:Event):void {
trace("completeHandler: " + event);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatusHandler: " + event);
}
private function initHandler(event:Event):void {
trace("initHandler: " + event);
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function openHandler(event:Event):void {
trace("openHandler: " + event);
}
private function progressHandler(event:ProgressEvent):void {
trace("progressHandler: bytesLoaded=" + event.bytesLoaded + " bytesTotal=" + event.bytesTotal);
}
private function unLoadHandler(event:Event):void {
trace("unLoadHandler: " + event);
}
private function clickHandler(event:MouseEvent):void {
trace("clickHandler: " + event);
var loader:Loader = Loader(event.target);
loader.unload();
}
在Flash播放器8以前的版本中并没有提供管理文件的功能,也没有一种机制用于上传和下载文件,因此大多数Web程序都是基于HTML的方式上传和下载文件,基于Flash的应用程序必须自己来实现上传和下载文件功能,从Flash播放8开始,系统提供了一套新的APIs 来支持文件的上传和下载。Flash 播放器允许用户浏览本地文件,并使用 FileReference 和 FileReferenceList 类上传和下载文件,本章将讨论这些 APIs 。
flash.net.FileReference 类定义了一个 download( ) 方法允许用户通过URL下载文件。当Flash播放器调用download( )方法时,它试图打开一个对话框,标题为"Select location for download.",这个对话框使用标准的系统对话框让用户选择文件保存路径。 在调用download( )方法之前,先构造一个FileReference 对象,如:
var fileReference:FileReference = new FileReference();
var urlRequest:URLRequest = new URLRequest("example.txt");
fileReference.download(urlRequest);
download( ) 方法本身没有暂停执行功能,一旦download( )方法被调用,Flash播放器就会试图打开保存对话框,要么成功打开对话框,要么抛出异常,而Flash播放器则继续执行下一行代码,也就是或系统并不知道用户是否已经选择了文件并点击保存按钮,因此需要监听select事件确定用户何时点击了保存按钮,select事件的类型为Event,使用Event.SELECT常量作为参数:
fileReference.addEventListener(Event.SELECT, onSelectFile);
在select事件中,通过FileReference对象的name属性可获得用户选择的文件名:
private function onSelectFile(event:Event):void {
trace(event.target.name);
}
当用户也可能点击保存对话框的Cancel按钮,如果用户点击了Cancel按钮,文件将不会被下载,对话框将关闭:
fileReference.addEventListener(Event.CANCEL, onCancelDialog);
我们可以通过progress事件监视文件的下载进度,在下载过程中FileReference对象会不断的发出ProgressEvent类型事件: fileReference.addEventListener(ProgressEvent.PROGRESS,onFileProgress); progress事件对象有两个属性,bytesLoaded和bytesTotal属性, 返回当前已下载字节数和总字节数,看下面的例子:
private function onFileProgress(event:ProgressEvent):void {
fileProgressField.text = event.bytesLoaded + " of " + event.bytesTotal + " bytes";
}
当下载完成时FileReference对象发出complete事件,类型为Event :
fileReference.addEventListener(Event.COMPLETE,onFileComplete);
使用FileReference或FileReferenceList对象的browse( )方法可以打开一个对话框用于浏览本地磁盘文件,唯一不同的是FileReference对象的browse( )方法只能选一个文件, 而FileReferenceList 对象可以选多个文件:
fileReference.browse( );
和download( )方法一样,browse( )方法也可能抛出异常,因此在调用时最好放在try/catch语句中执行并处理可能的异常,导致illegal operation error异常可能有两种可能:一次只能打开一个浏览对话框,如果再次调用browse( ),就会抛出IllegalOperationError。如果用户对全局Flash播放器设置为不允许文件浏览,则调用browse( )方法时抛出该异常。
下面的代码段演示如何在TRy/catch块中处理IllegalOperationError异常:
try {
fileReference.browse();
} catch (illegalOperation:IllegalOperationError) {
// code to handle error
}
默认下browse( )方法打开的对话框显示用户系统中的所有文件,可以通过设置过滤器只显示特定类型的文件,比如只显示图形文件或文本文件,设置的方法是把flash.net.FileFilter对象数组作为参数传递给browse( )方法。
FileFilter构造器至少需要两个参数:
- 第一个参数决定在下拉列表中显示什么文件类型:
- 第二个参数决定显示的文件扩展名。
多个文件扩展名需用分号分开,如下面的例子只显示三种类型的图形文件:
var fileFilter:FileFilter = new FileFilter("Images", "*.png;*.gif;*.jpg");
可以在调用browse( )方法时进行过滤设置:
fileReference.browse([fileFilter]);
下面的代码只设置了一个过滤器,还可以一次传入多个过滤器,如:
var fileFilter1:FileFilter = new FileFilter("Images", "*.png;*.gif;*.jpg");
var fileFilter2:FileFilter = new FileFilter("Documents", "*.txt;*.doc;*.pdf;*.rtf");
var fileFilter3:FileFilter = new FileFilter("Archives", "*.zip;*.tar;*.hqx");
var fileFilter4:FileFilter = new FileFilter("All", "*.*");
_fileReference.browse([fileFilter1, fileFilter2, fileFilter3, fileFilter4]);
当用户选择了文件并点击了Open按钮后FileReference对象会发出select事件,类型为Event,可通过Event.SELECT常量注册监听器:
fileReference.addEventListener(Event.SELECT, onSelectFile);
当用户选择了文件后, 关于文件的信息 (如文件名, 大小, 创建时间等) 都会保存在FileReference对象里:
selectedFileTextField.text = fileReference.name;
如果用户点击了Cancel按钮,FileReference对象会发出cancel事件,类型为Event。可通过Event.CANCEL常量注册监听器:
fileReference.addEventListener(Event.CANCEL, onCancelBrowse);
这两个事件同样适用于 FileReferenceList 对象
FileReference对象的upload( )方法允许使用服务端脚本通过HTTP(s)上传文件, upload( )方法至少需要一个为URLRequest类型的对象作为参数,用于指定服务端脚本的URL:
var urlRequest:URLRequest = new URLRequest("uploadScript.cgi");
fileReference.upload(urlRequest);
所有上传使用POST传输方式,Content-Type为multipart/form-data。默认下Content-Disposition设置为Filedata, 因为脚本需要知道Content-Disposition值以便读取文件数据。 如果脚本需要Content-Disposition其他值,可通过upload( )方法第二个参数设置:
fileReference.upload(urlRequest, "UploadFile");
如果是调用FileReferenceList对象,那根据fileList属性必须为每个文件调用一次upload( )方法,FileReferenceList对象的fileList属性就是FileReference对象数组。 upload( )方法抛出的异常和 download( )方法相同, 比如都会抛出 security 异常事件和 IO 异常事件。 监视文件上传进度和监视下载进度一样, 当文件上传时FileReference对象发出progress 事件,完成时发出completed事件。
有时候会有这样的需求,需要 ActionScript 3.0(AS3) 于 JavaScript(js) 之间互相调用。
在 AS3 中直接调用 js中的函数:
ExternalInterface.call('javascript_function');
javascript_function 就是html页面的一个 JavaScript 的函数。
在 js 中调用 AS3 的函数,需要在 AS3 中注册要被 js 调用的函数:
ExternalInterface.addCallback('javascript_callback', actionscript_method)
public function actionscript_method(value:Object):void { // }
注册后会将 JavaScript 中调用的函数 javascript_function 映射到 AS3 中的方法 actionscript_methond中。
js 代码:
var movie = document.getElementById("gameId");
movie.javascript_callback(value);
这里调用了 javascript_callback 并传递了参数value,那么就可以直接调用到 AS3 中的方法
在什么情况下需要这样使用呢,真实的例子,腾讯平台或者是Facebook都提供有邀请好友的功能,那么我们在游戏中需要邀请腾讯上的QQ好友就需要用到,腾讯提供了js的API,加载他们提供的API的js 文件代码后,就可以直接使用他们提供的 API,通过在游戏中调用腾讯提供的 js API 函数,发送邀请好友请求,然后会弹出邀请好友界面,选择好友,点击确定后,腾讯API提供回调功能,在js回调函数中编写调用AS3的函数来回调到flash中,来执行发奖励等操作,下次读者开发的应用或者游戏有机会上平台就可以用上了。
SourceMate 是 Flash Builder 开发工具的一个插件,非常好用的,可以设置代码快速生成模板,可以给整个文件快速导入所有累,提供重构许多工具,变量提取等。再加上自定义自己的高速快捷键,开发AS3项目时就如虎添翼了。
- 目录
- 下一章: 理解Flash的沙箱