搜索

  •  

使用TimelineWatcher类让时间轴标签发送事件

出自9RIA.com WIKI

跳转到: 导航, 搜索

原文:Using timeline labels to dispatch events with the ActionScript 3.0 TimelineWatcher class
作者:Bobby van der Sluis
译者:rainfly

点击此处查看或参与讨论吧^_^点击此处查看或参与讨论吧^_^

目录

介绍

在许多SWF应用程序中,开发人员需要用程序监视时间轴,当播放到一个帧标签或者到最后一帧时能够执行一些动作。但是,实现这一点的技术却常常与把时间轴跟动作代码分离的设计目标相冲突。

在过去的十年中,Adobe Flash已经从单一的动画工具发展成为创建丰富内容的综合开发环境。现在,许多富媒体机构都有一套工作流程:许多不同角色的人——包括Flash设计人员和开发人员——可以在一个项目或按照特定的框架、概念结构分割成了多个不同FLA和ActionScript文件的多个项目中同时开发。

把多媒体元素和时间轴动画做在FLA文件里,把所有的逻辑放到外部ActionScript文件中是非常好的做法。为此,Flash CS3 Professional引入了文档类,作为FLA文件连接外部ActionScript代码的默认机制。

总体而言,把时间轴跟动作或代码分离已经变得很简单了。但是,却有一个例外存在。

考虑这种情况:一位开发人员想要在一个时间轴播放到一个特定的以标签标记的位置时运行一小段代码。它如何才能准确的知道何时播放到那一点?为了解决这个问题,开发者可能把下面这段代码放到FLA文件的时间轴上:

dispatchEvent(new Event("animationHasFinished"));

虽然这样做也能实现想要的效果,但是它是有缺点的。对开发者而言,时间轴代码比外部ActionScript文件中的代码更难开发、调整及定位。许多开发者也会认为这种方法太幼稚。最后它破坏了代码和时间轴分离的原则(是的,我们“Flasher”是自尊心很强的人)

我在Refunk工作的时候,我们开发了一个小的实用工具可以很好的解决这个问题。TimelineWatcher 类允许开发者的代码监视时间轴,当到达一个带标签的帧或者是时间轴的末尾时发出通知。通过像钩子一样使用帧标签——就像视频里的cue点——时间轴和代码可以真正分离了。

需求

要完成本教程,你需要安装下列软件和文件:

Flash CS4 Professional

示例文件:

前提知识

你应该对Adobe Flash Professional和ActionScript 3.0有很好的理解。

TimelineWatcher和TimelineEvent类

TimerlineWatcher类是一个小的、简单实用的类。下面是有用的文档:

包: com.refunk.timeline

类: public class TimelineWatcher

继承: TimelineWatcher > EventDispatcher > Object

语言版本: ActionScript 3.0

公共方法

TimelineWatcher(timeline:MovieClip): 创建一个监视单个时间轴的TimelineWatcher对象

dispose():void: 删除TimelineWatcher对象的内部监听器和引用,这样它就会被垃圾回收而不会有内存泄漏。

Events

labelReached: 当播放到新的时间轴标签时发送

事件对象类型: com.refunk.events.TimelineEvent
Event.type 属性: com.refunk.events.TimelineEvent.LABEL_REACHED
自定义属性/值:

currentFrame: 当前帧 (int)

currentLabel: 当前时间轴标签 (String)

endReached: 当播放到时间轴最后一帧时发送

事件对象类型: com.refunk.events.TimelineEvent
Event.type 属性: com.refunk.events.TimelineEvent.END_REACHED
自定义属性/值:

currentFrame: 当前帧 (int)

currentLabel: 当前标签 (String)


因为TimelineWatcher类继承自内置的EventDispatcher类,因此你可以使用标准的addEventListener方法添加事件监听器。另一个类是TimelineEvent,它是自定义的TimelineWatcher使用的事件类。这些事件存储了当前帧和当前标签,所以可以通过事件对象获取这些信息。

你可以在本文的示例文件(timelinewatcher.zip)中找到TimelineWatcher和TimelineEvent类。这两个类都有[www.refunk.com Refunk]免费提供,并依照GNU General Public License发布。

安装timelinewatcher示例

要查看TimelineWatcher的例子,先解压timelinewatcher.zip文件,然后使用你的Web浏览器打开index.html(确保你有Flash Player9 或更高版本)。你会看到一个简单的时间轴动画:一个红球从左移动到右,然后再移动回去。在动画停止前会循环3次。左上角的文本框显示当前播放的标签和循环的次数(看图1)。

fig01.jpg

图1.简单的TimelineWatcher例子

在你的Flash开发环境中打开test.fla,你会看到一个红球影片剪辑在白色画布上(图2)。

fig02.jpg

图2.画布第1帧显示一个红球

主时间轴包含两个普通的动画,一个是把球移动到右侧,另一个是把球移回左侧,另外还有2个帧(或时间轴)标签——moveRight和moveLeft——指示动画的方向(图3)

fig03.jpg

图3.时间轴显示2个简单的动画和对应的帧标签

本例子中的设计工作就完成了。如果测试影片的时候不添加文档类,你会看到红球无休止的来回移动。

接下来要添加一个完成如下工作的外部ActionScript文件:

  • 在画面左上角放置一个动态文本框显示当前时间轴标签及已经循环的次数
  • 循环3次后让动画停止

要把名为Test.as的ActionScript文件链接到test.fla文件,在属性面板的发布设置(图4)中键入Test作为类。在编译时这个文档类会关联到主时间轴,并能提供跟主时间轴上的代码几乎一样的功能。

fig04.jpg

图4.属性面板中的文档类框

在测试外部ActionScript文件之前,你还需要知道一个设置。选择 文件 > 发布设置,然后添加Flash选项卡。确保Script菜单中选中了ActionSript 3.0,然后点击设置,打开高级ActionScript 3.0对话框(图5)。

fig05.jpg

图5.高级ActionScript 3.0设置对话框中的自动声明舞台示例复选框

自动声明舞台示例复选框默认是选中的,也就是说Flash会在编译时自动使用实例名字声明主时间轴上的元素。尽管这个功能对设计者和使用Flash开发工具开发代码的开发人员很实用,却会给使用外部代码编辑器的开发者带来问题,因为这些编辑器会抱怨说还没有声明。(Flash会当作它们已经被创建了——在内存中为你创建——所以并不会出现问题; 需要它们,但是它们不存在,Flash会自动创建它们)

为使你的代码可以在多种开发环境下编辑,你最好取消这个选择并明确声明主时间轴上的元素为文档类的公共变量。没有这些声明,Flash会抛出编译期错误。本例子中,主时间轴上只有一个实例名为ball的影片剪辑,所以需要下面的声明:

public var ball:MovieClip;

现在你就有了对主时间轴上的ball实例的引用。

使用外部ActionScript把所有元素整合起来

下面是名为Test.as的文档类的基本骨架:

package {
 
    import flash.display.MovieClip;
 
    public class Test extends MovieClip {
 
        public var ball:MovieClip;
 
        public function Test() {
            super();
            stop();
        }
    }
}

上面的代码声明了主时间轴上的ball影片,并停止播放。尽管Flash会在构造函数中隐式的调用super()方法,我习惯于在所有的扩展类中添加上它;它会提醒我不要忘记那些需要附加参数的调用。在上面这些代码的基础上,我在画面的左上角添加了一个显示当前时间轴标签的文本框(高亮文本为新添加的代码):

package {
 
    import flash.display.MovieClip;
    import flash.text.TextField;
 
    public class Test extends MovieClip {
 
        public var ball:MovieClip;
        private var output:TextField;
 
        public function Test() {
            super();
            stop();
            output = new TextField();
            addChild(output);
            output.text = "testing: 1, 2, 3"; // just for testing purposes
        }
    }
}

从现在起事情将变得越来越有趣。我要添加TimelineWatcher和TimelineEvent类及相关的逻辑:

package {


 
    import flash.display.MovieClip;
    import flash.text.TextField;
    import com.refunk.events.TimelineEvent;
    import com.refunk.timeline.TimelineWatcher;
 
    public class Test extends MovieClip {
 
        public var ball:MovieClip;
        private var output:TextField;
        private static const MOVE_LEFT:String = "moveLeft";
        private static const MOVE_RIGHT:String = "moveRight";
        private var timelineWatcher:TimelineWatcher;
 
        public function Test() {
            super();
            stop();
            output = new TextField();
            addChild(output);
            timelineWatcher = new TimelineWatcher(this);
            timelineWatcher.addEventListener(TimelineEvent.LABEL_REACHED, handleTimelineEvent);
            gotoAndPlay(1);
        }
 
        private function handleTimelineEvent(e:TimelineEvent):void {
            if (e.currentLabel === MOVE_LEFT || e.currentLabel === MOVE_RIGHT) {
                output.text = "label: " + e.currentLabel;            }        }
    }


}

首先我导入了这2个类,让Flash编译器知道在哪里能找到它们。接下来我添加了两个名为MOVE_LEFTMOVE_RIGHT的常量与时间轴标签对应。这种做法能够很好的避免书写错误。

接下来,我声明了TimelineWatcher的实例,名字是timelineWatcher,为私有变量。在主构造函数Test()中,生成了真实的TimelineWatcher实例,并把要监视的时间轴作为参数传递给它。在这里我可以使用this关键字,因为它指向主时间轴。

另外还添加了对TimelineEvent.LABEL_REACHED事件的监听器,它会触发自定义的handleTimelineEvent()方法。然后,让主时间轴开始播放。

方法handleTimelineEvent()通过返回的事件对象e获取当前标签,并检查它是否跟我要监视的预定义的标签匹配。如果匹配,将会把时间轴标签显示在画面上。

如果运行这个例子,你会发现红球不停的来回运动,当前标签会显示在画布左上角。在添加了很少几行代码后,我们就可以不需要在时间轴上添加代码也能准确的知道主时间轴的播放情况了!

下面的代码是当时间轴播放3次后让它停止:

package {


 
    import flash.display.MovieClip;
    import flash.text.TextField;
    import com.refunk.events.TimelineEvent;
    import com.refunk.timeline.TimelineWatcher;
 
    public class Test extends MovieClip {
 
        public var ball:MovieClip;
        private var output:TextField;
        private static const MOVE_LEFT:String = "moveLeft";
        private static const MOVE_RIGHT:String = "moveRight";
        private var timelineWatcher:TimelineWatcher;
        private var loops:uint = 1;
 
        public function Test() {
            super();
            stop();
            output = new TextField();
            addChild(output);
            timelineWatcher = new TimelineWatcher(this);
            timelineWatcher.addEventListener(TimelineEvent.LABEL_REACHED, handleTimelineEvent);
            timelineWatcher.addEventListener(TimelineEvent.END_REACHED, handleTimelineEvent);
            gotoAndPlay(1);
        }
 
        private function handleTimelineEvent(e:TimelineEvent):void {
            switch (e.type) {
                case TimelineEvent.LABEL_REACHED:
                    if (e.currentLabel === MOVE_LEFT || e.currentLabel === MOVE_RIGHT) {
                        output.text = "label: " + e.currentLabel + "\nloops: " + loops;
                    }
                    break;
                    case TimelineEvent.END_REACHED: loops++;
                    if (loops > 3) { stop();
                         timelineWatcher.removeEventListener(TimelineEvent.LABEL_REACHED, handleTimelineEvent)                       
                         timelineWatcher.removeEventListener(TimelineEvent.END_REACHED, handleTimelineEvent);                         
                         timelineWatcher.dispose();
                         timelineWatcher = null;
                    }
                    break;}
        }
    }


}

我添加了第二个监听器,监听TimelineEvent.END_REACHED事件,计算播放次数,并在播放3次后停止它。

最后,就是清理工作,删除两个监听器,摧毁TimelineWatcher实例,并把它的引用设置为null

本例子中的所有代码都写好了。如果你测试影片,应该会看到图1的内容。

接下来做什么

在本文中你学会了如何使用TimelineWatcher类在播放到帧标签或到时间轴末尾时发送事件,并保持时间轴和代码的分离。

ByteArray.org的Thibault Imbert写了一篇文章:FrameLabel event,希望下一个版本的Adobe Flash Player能实现这个功能。

更多关于ActionScript的知识,请访问ActionScript 技术中心

附:要求Flash Player 11新增功能——FrameLabel(Event.FRAME_LABEL)

原文:http://www.bytearray.org/?p=603

译文如下:

我相信一些人已经考虑过这个了:

// retrieve a frame label on the timeline
var myFrame:FrameLabel = this.currentLabels[1];
 
// listen for Event.FRAME_LABEL dispatched when frame is reached
myFrame.addEventListener ( Event.FRAME_LABEL, onFrameLabel );
 
function onFrameLabel ( e:Event ):void
{
// do stg
}

它将会替换非官方的、受限制的addFrameScript方法,并极大改善在时间轴上写代码。

是的!我依然很喜欢使用时间轴

如果你想看到这项功能,就来投票吧!

本页面已经被浏览11,372次。
CopyRight © 2007-2012 北京冠游时空数码技术有限公司, All Rights Reserved.
9RIA.com 天地会 京ICP备11007422号-2