Skip to content

June 25, 2010

5

Building an AS3 FLA based component with a SWFPanel and a LivePreview

In learning how to make AS3 components I found a large amount of frustration with Adobe’s documentation. Every useful resource I found had a slightly different (yet valid) approach to the finer points of component development. It seems everyone has a different solution depending on their requirements, so be prepared to read a lot before you dive in.

The online resources I used were:

Example files:

My finished files are available here for download. Because this component requires some absolute filepath parameters I recommend:

  • Placing the extracted directory at the root level of your ‘C’ drive
  • Macintosh users will need to replace the current ‘c|’ characters with the relevant drive name and delimiter characters.

OK, on with development…

My requirements

I needed a component that could be used by (low tech-savvy) design staff to preview external text in the Flash IDE. The text is HTML tagged CDATA within an XML document. The project uses embedded fonts too, so it was critical that what appeared in the IDE was exactly what appeared in the published SWF.

In a nutshell, I needed an AS3 component with a LivePreview (to load and correctly display the embedded fonts), and a SWFPreview (to display the component parameters in a more legible fashion that the standard Flash component parameters panel).

Image of XMLTextArea components onstage in the Flash IDE

This image shows XMLTextArea Component instances displaying CSS styled HTMLText in the Flash CS4 IDE with an embedded font (the font is NOT an active Windows font, it's embedded in a SWF that's loaded for use by the LivePreview). Note the list items in the bottom instance, they're indented using CSS, not by the addition of 'space' characters into the text.

Step 1: Creating the ‘shell’

Setting up a development workflow is straightforward as long as you remember the 3 elements of the component (runtime, live preview, SWF panel). I made a directory with some empty FLAs first:

  • XMLTextAreaComponent.fla (to contain and test the component during development)
  • XMLTextAreaComponentLivePreview.fla (to build the LivePreview SWF that you’ll see in the Flash IDE while authoring with component), and
  • XMLTextAreaComponentSWFPanel.fla to develop a functional UI instead of using the Component Parameters panel.

Next, create the Document classes for each of these FLAs. Using a consistent naming convention throughout development is critical, it lets me focus on the problems that need solving instead of wondering which class or fla I’m looking at. The Document classes are named as follows:

  • com.ui.textarea.component.XMLTextAreaComponent.as
  • com.ui.textarea.component.XMLTextAreaComponentLivePreview.as
  • com.ui.textarea.component.XMLTextAreaComponentSWFPanel.as

You can download my finished Flash CS4 (Windows) files from here. I’d recommend putting the directory at the root of your ‘C’ drive, that way you couldn’t need to change any of the component instance parameters to see the XMLTextAreaComponentTest.fla functioning correctly.

Step 2: Build the SWFPanel

For me, the SWFPanel is the logical place to start. It focuses attention on the functional requirements of the component. The XMLTextArea needs a relatively large amount of startup configuration (text source, stylesheet, external fonts, author-time and runtime location info) that would be inconvenient to set using the standard Component Parameters panel.

The component SWFPanel populated with parameters

This image is a populated SWFPanel for one of the onstage instances of the component. This is currently quite clumsy looking, but it points each instance to its XML text file, SWF containing the embedded fonts and stylesheet at runtime and author-time.

First I laid out my SWFPanel UI (XMLTextAreaComponentSWFPanel.fla), then named my component instances. I always have ‘Automatically declare stage instances’ turned off in my FLAs, so in the com.ui.textarea.component.XMLTextAreaSWFPanel class you’ll see I’ve declared each component instance as follows:

public var stylesheetSource_ti:TextInput;
public var pathPrefix_ti:TextInput;
public var xmlSource_ti:TextInput;
public var placeholder_ti:TextInput;
public var textNode_cb:ComboBox;
public var fontSource_ti:TextInput;
public var httpRoot_ti:TextInput;

When we change something in the SWFPanel we need to communicate that change explicitly to the selected onstage instance of the component. Conversely, the SWFPanel also needs to be initialised with the onstage component instance parameters. Here are the JSFL commands to retrieve the onstage instance values:

private const PATHPREFIX:String = "fl.getDocumentDOM().selection[0].parameters.pathPrefix.value";
private const XML_SOURCE:String = "fl.getDocumentDOM().selection[0].parameters.xmlTextPath.value";
private const FONT_SOURCE:String = "fl.getDocumentDOM().selection[0].parameters.fontSource.value";
private const STYLESHEET_SOURCE:String = "fl.getDocumentDOM().selection[0].parameters.stylesheetSource.value";
private const HTTP_ROOT:String = "fl.getDocumentDOM().selection[0].parameters.httpRoot.value";

…and here’s how we populate the SWFpanel (see the init() method of the XMLTextAreaSWFPanel class) when an instance of the component is selected onstage:

pathPrefix_ti.text = MMExecute(PATHPREFIX);
xmlSource_ti.text = MMExecute(XML_SOURCE);
fontSource_ti.text = MMExecute(FONT_SOURCE);
stylesheetSource_ti.text = MMExecute(STYLESHEET_SOURCE);
httpRoot_ti.text = MMExecute(HTTP_ROOT);

Lastly, we need to update the component parameters of the onstage instance whenever we use the SWFPanel to make changes. I do that with event listeners that issue more JSFL commands, like so:

xmlSource_ti.addEventListener(Event.CHANGE, onXMLSourceChanged);

private function onXMLSourceChanged(event:Event):void {
        MMExecute('fl.getDocumentDOM().selection[0].parameters.xmlTextPath["value"] = "' + xmlSource_ti.text + '"');
}

The rest of the XMLTextAreaComponentSWFPanel class just implements these concepts for all the other UI widgets. The important concepts are:

  • the SWFPanel uses JSFL to communicate with the onstage instance
  • it’s one-way communication, the SWFPanel does all the work of interrogating onstage instances and updating itself
  • the component instance can’t dynamically talk to the SWFPanel, other than when it’s selected, and that’s only to expose its component parameters.

To test the JSFL communication we need to connect the SWFPanel up to a component instance, so the next step is to build a basic version of the component, give it some parameters and connect it to the SWFPanel.

Step 3: The Component – parameters

OK, next I create the basic component. Make a MovieClip, then in the Library right-click and select ‘Component Definition’. For this one I enter the Class as ‘com.ui.textarea.component.XMLTextAreaComponent‘ and point the ‘Custom UI’ field to ‘XMLTextAreaComponentSWF.swf‘. During development I prefer to use the ‘Custom UI in external .swf file’ option. It makes updating much quicker if I make changes to the SWFPanel for any reason. In addition to setting the class in the component definition I also needed to set the Linkage ID in the ‘Properties’ panel.

Because I’m still a component newbie (and it’s hard enough to keep track of the basics right now), I’ve chosen to extend the UIComponent class and override the ‘configUI()’ method. I set up my component clip with the same 2 frame structure discussed in the Jeff Kamerer articles on the Adobe site and it worked for me (i.e. compiled without errors) immediately.

Once you’ve linked the component clip in your Library to the component class file you’ll find that any changes you make to the ‘Parameters’ list in the ‘Component Definition’ panel won’t be saved. This is because the component now looks to the Class you nominated for its’ parameters. These need to be defined with getters and setters like so:

private var _httpRoot : String;

[Inspectable (name="httpRoot" defaultValue="")]
public function set httpRoot( value : String ) : void {
        _httpRoot = value;
}

public function get httpRoot( ) : String {
        return _httpRoot;
}

I found that unless I included the ‘name’ parameter in the ‘Inspectable’ metadata the component parameter wasn’t available to me from JSFL in the SWF panel. Dunno why, it just worked for me this way. This process was repeated for all component parameters, then I right-clicked the component movieclip in the Library and chose ‘Component Definition’, and clicked ‘OK’ again. We need to do this anytime we make changes to the component class that would affect it’s functionality in the Flash IDE. Since we’ve just added component parameter getters and setters in the component class we need to update it before it can be properly tested.

Now I tested the communication between my SWFPanel UI widgets and the onstage component instances.

Step 4 – The LivePreview

This is probably my favourite part of FLA-based component development because it brings completely customised functionality and appearance to the Flash IDE. From within the IDE the LivePreview loads the fonts, CSS and HTML, and renders the text onscreen exactly as it renders at runtime. Designers can work with visible, correctly styled external HTML text, and all the text remains external to the FLAs (so translation or revision can be completed with no recompiling).

The basic framework of a LivePreview SWF can be seen in my example files:

  • The Document Class of the LivePreview.fla should be set to fl.livepreview.LivePreviewParent
  • In frame 1 on the timeline, a clip (with a Linkage to the XMLTextAreaComponentLivePreview class) that contains an onstage instance named ‘avatar_mc’. (I also included a TextArea component and some dynamic TextFields, but later converted these to guide layers, they’re still present in my example files).
  • The XMLTextAreaLivePreview class extends UIComponent and overrides the setSize() and draw() methods
  • All the component parameters need getters and setters in the XMLTextAreaLivePreview class to access their values in the IDE at authoring time.

All the action in my component happens in the draw() method after the fonts, XML and CSS are loaded and parsed.

NB: The onstage LivePreview won’t update dynamically while you’re resizing it. This is also a constraint of the components provided by Adobe, so I didn’t stress too much about finding a solution. If you have one, please leave a note in the comments.

Step 5 – Deployment

All our Flash team members (designers and developers) are also connected to our classes via SubVersion. Currently the component is in ‘beta’, being tested by a couple of key staff, so I haven’t yet prepared an MXP for distribution. When that happens I’ll add my notes here.

Finally

There’s one more ‘dirty little secret’ in this component. When I changed the ‘visibleXMLText’ component parameter in an onstage instance, it wouldn’t automatically refresh the view (even though it could trace out the updated text) so I used JSFL to deselect and reselect the component in question (found the technique here). Unfortunately it breaks the Flash ‘undo’ functionality for any onstage instance of this component. Yes, it sucks, but it’s not a showstopper. Again, if you have an idea that might work, tell me in the comments please.


5 Comments Post a comment
  1. Nov 1 2011

    Download does not work. Requires class:
    de.betriebsraum.utils.FontManager

    Reply
    • Nov 1 2011

      Sorry about that – I’ve added the necessary class to the download.

      Reply
  2. Jay
    Nov 30 2011

    Thank you for your quick response. I should have checked back sooner.
    Unfortunately, either download will not work properly for me. The published swf displays correctly which is great. However, the live preview in CS5 is not working, just empty boxes, and no UI display despite moving to the directory stated in the component definitions.

    I am baffled on what would cause this.
    Any advice?

    Reply
  3. Jay
    Nov 30 2011

    UPDATE: now the original swf from the download will not display. Very frustrating.

    Reply

Trackbacks & Pingbacks

  1. Adventures in Component Writing for Flash AS3 - EqSim

Share your thoughts, post a comment.

(required)
(required)

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments