Monday, 13 July 2009

Interacting with embedded Flash content in Flex

I've been doing some Flex development lately (sorry Microsoft), so I though I might share a little discovery of mine in return to numerous advices from the community.

While creating a complex Flash application, it is a common situation that the graphical content and animations created by designers in Flash, while developers load them into a Flex application. While loading is pretty straightforward, often you need to manipulate them, i.e., play a different clip, detect then a clip reaches a certain label, etc. What you usually do is have your flash content have a certain base class (called Document class) which is known to your flex app, and cast loader.content to this class once it's loaded.

The problem is, the above solution doesn't work with embedded content. Don't know whether it is a bug or a feature, but the content cannot be cast to the document class. The docs say, use embedded content for static stuff like images or static swfs. Well, my content was an intro to a module, and I had to detect it's finished playing in order to hide it and show the actual content. On the other hand, I wanted it embedded so that my preloader would work correctly. In addition, the module had a base class, and I wanted to have the intro-related code in the base class, while embedding the intro into the actual module.

So, utilizing some hints from the community plus a little debugging session, and here's my solution (I still don't see any reason why it works this particular way).

  1. Embed the flash content via the metadata tag:
    [Embed(source="../../flex_bin/someflash.swf", mimeType="application/x-shockwave-flash")]
    private var SWFBytes:Class;
  2. Use it in your SWFLoader (note the source):
    <mx:swfloader id="introLoader" source="{new SWFBytes()}" scalecontent="false" creationcomplete="intro_complete(event)">
  3. Handle the CreationComplete event like this:
    var content:MovieClip= this["introLoader"].content as MovieClip;
    var loader:Loader = content.getChildAt(0) as Loader;
    var intro:RoomIntro = RoomIntro(loader.content);
Here's the "intro" variable we're interested it, RoomIntro is the document class of the flash movie. Note that the content of our loader is a movie clip, but it's not what we need: it has a child, which is another loader, and the content of *this* loader is what we actually need. In short, we need the content of the first child of the content of our loader.

Tricky, eh?