I found dealing with listeners really annoying, especially during simple, repetitive tasks in Flash CS tool (mainly, due to lack of code generation). That inspired me to think about convenient solution, and later on, code it.
I wanted to use best, known to me techniques. As a result, Fingers are extensively TDD'ed with ASUnit & Hamcrest, they are crafted with huge help of IntelliJ Idea, and finally they use cool, out of the box solutions.
Fingers are designed to be tiny (2KB), that's why I like to say about them as about micro AS3 extension. Their only job is to simplify AS3 event management, make your code shorter and more readable. Technically speaking Fingers are a wrapper for any IEventDispatcher.
As an example, let's take a look at the following code:
Pure AS3 code:
obj.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { nextFrame(); })
Fingers equivalent:
on(btn).click += nextFrame;
What we've done is added listener to a button, so after clicking a button,nextFrame() method is called.
Another example in pure AS3 - preloading:
loaderInfo.addEventListener(ProgressEvent.PROGRESS, loaderInfo_progressHandler); loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler);
Fingers version:
on(loaderInfo).progress += loaderInfo_progressHandler; on(loaderInfo).complete += loaderInfo_completeHandler;
If we want to clean after ourselves, we typically type:
loaderInfo.removeEventListener(loaderInfo_progressHandler); loaderInfo.removeEventListener(loaderInfo_completeHandler);
Fingers alternative:
on(loaderInfo).removeAllListeners();
or...
on(loaderInfo).progress -= loaderInfo_progressHandler; on(loaderInfo).complete -= loaderInfo_completeHandler;
Enough? Install Fingers from swc or download source code. Don't forget to read the rest of this tutorial.
Yes, it's the MovieClip.nextFrame method. To make Fingers most effective, +/- operators were overrided. As a result of that you can:
// set/override listeners: on(btn).click = nextFrame ; // add listeners: on(btn).click += nextFrame + btn_clickHandler; // remove listeners: on(btn).click -= nextFrame + btn_clickHandler;Please note, that you don't have to import on function, it's global (for convenience reasons).
on(yourClassInstance).yourEvent += yourListener;
// on button click call my function // ↓ ↓ ↓ ↓ on( btn ).click += myFunction;so, the general syntax is following
on(o:IEventDispatcher).<eventType> <operator: =, +=, -=> <yourFunctions>
where:
on(btn).click += listener1 + listener2;
Beware to finish on statement with a proper method call (see more).
Please note, that every time I use one of these terms: "on() listeners", "listeners ... through on() syntax", I'm talking about listeners which were added/removed through on() statement (in contrast to these ones added through native addEventListener/removeEventListener/...).
function typicalListener(e:Event):void { trace(e); }and the short ones
// so these without arguments function shortOne1():void { // body } // or with unlimited number of optional arguments function shortOne2(p:Object = null, p2:Object = null):void { // body }
It's up to you, which one will you use.
By setting listener(s), you remove all the previous listeners added through on(). It's important to remember, that listeners added through native addEventListener() aren't removed.
on(btn).click += nextFrame; on(btn).click = prevFrame;
In second line of above example the nextFrame handler was removed, and then prevFrame handler was added.
(If you're here, you surely know how to add listeners in Fingers - sorry for duplicating).
It's easy - you can add listeners, using following syntaxon(btn).click += btn_clickHandler;
Listeners added through on() can be removed using native removeEventListener() (it applies only to listeners with one e:Event argument):
on(btn).click += someListener; btn.removeEventListener(MouseEvent.CLICK, someListener); trace(btn.hasEventListener(MouseEvent.CLICK)) // false;
// prepare btn.addEventListener(MouseEvent.CLICK, yourListener); // remove one listener on(btn).click -= yourListener+0; // or btn.addEventListener(MouseEvent.CLICK, yourListener1); btn.addEventListener(MouseEvent.CLICK, yourListener2); // remove multiple listeners on(btn).click -= yourListener1 + yourListener2+0 is to omit compile error. In this way you can say compiler, to treat Function as an int. This could be done also in a way of simple cast: int(yourListener), however +0 version seems cleaner, shorter and more convenient to me. Another way to solve this is to turn off "strict compiler mode", but I wouldn't recommend that.
// prepare
on(btn).click += listener1;
on(btn).click += listener2;
on(btn).click += otherFunction;
// remove all `click` listeners (added through on)
on(btn).click = null;
// prepare
on(btn).click += btn_clickHandler;
on(btn).mouseDown += btn_mouseDownHandler;
on(btn).mouseUp += btn_mouseUpHandler;
// remove all btn listeners (added through on)
on(btn).removeAllListeners();
Fingers can be used to dispatch native AS3 events (so they works, even if you use traditional addEventListener). So instead of such construction:
btn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));you can write:
on(btn).click();This will work, however it's not exactly the same. Code above dispatches an instance of Event class, if you'd like to dispatch MouseEvent, you should write on(btn).click(MouseEvent);
You can pass more parameters to dispatched event, as shown in the following method signature
on(obj).<eventType>(eventClass:Class = flash.events.Event, ...eventParams);
Assume, that we'd like to simulate download progress, by dispatching ProgressEvent
on(loaderInfo).progress(ProgressEvent, false, false, 20, 200);
// ↑ ↑ ↑ ↑ ↑
// | bubbles | bytesLoaded |
// eventType cancealable bytesTotal
again, in pure AS3 that can be achieved with following code:
loaderInfo.dispatchEvent( new ProgressEvent(ProgressEvent.PROGRESS, false, false, 20, 200) );
f$(yourFunction:Function)(args...)so, let's say we want our button to trace("button clicked") after clicking. We can achieve this, with one line:
on(btn).click += f$(trace)("button clicked");It's same as if you'd write:
on(btn).click += function():void { trace("button clicked"); }Freezer comes really handy when prototyping tweens, e.g. with Tweener:
on(btn).click += f$(Tweener.addTween)(btn, {alpha: 0});
Please note:
There are three restrictions, while using Fingers:
Fingers use AS3 native events, so they are as quick as native ones (during event dispatching/handling). However there is some overhead while using on(..).. statement, what I guess is tolerable in common cases.
Size is small - Fingers in your project add 2 kB to the resulting SWF.
Cheers,
Filip Zawada
@Filip_Zawada
me@filimanjaro.com
Last edited: Sat, 25 Feb 2012