05.04
A work-flow for component creation
Introduction
The new component architecture in Flash CS3 is a vast improvement on the V2 component architecture used in Flash MX2004 and Flash 8. Fundamentally, the problem with the V2 architecture was that skinning a component was unintuitive at best and painful the rest of thee time. This meant that they were unsuited to the people who would benefit from them the most, namely the large Flash designer community who gain from the functionality of components but don’t have the skills or patience to go through some monster skinning process. This walkthrough is intended to describe the work-flow of component creation. It does not cover any of the details of actually coding components or any of the architectural details of the new fl.core.UIComponent class.
With the arrival of Flash CS3, Adobe has introduced a new component architecture that no longer uses the .SWC file as a container for ActionScript3 components. Components are now delivered to the end user in the form of a .FLA file. A correctly formed .FLA file placed in the correct folder [ $(AppConfig)/ Components ] will present the components that it contains in the components panel of the Flash IDE.
When the end user drags a FLA based component out of the components panel into their Flash document, a number of things happen:
An instance of the component is created in the document. At author-time, a live preview is displayed, which generally uses the default skin of the component.
A number of additional items are also imported in to the library. Mainly these are the skins of the component, and also a mysterious compiled clip called ComponentShim (more about this later…)
The very thought of handing a V2 component to a designer for them to reuse, was in my opinion, quite a laughable concept. This is where the new .FLA based components really shine.
The real advantage of FLA-based components is that the user is now able to double click the component, and edit the library resources that it uses. This means that components no longer feel locked-down, and the look of the component can be easily customized without a degree from the Macromedia V2 School of Rocket Scienceâ„¢. This paves the way for components to start being really useful in situations where there are clear divisions between programming and design. With the advent of ActionScript 3, it’s possible that the gap between development-oriented and design-oriented Flash users will widen. The new component architecture offers a bridge over the chasm.
I’m not going to spend too long describing how to use the new components. This is well covered in the CS3 documentation, and there is more info over at Aral’s blog.
My interest in components is from the perspective of a programmer lacking in design skills. Components will allow me to deliver easily re-usable functionality without tying the users of the component to my (rather poor) concept of a look and feel. So I need to know how to make component .FLA files that work in the same way as the ones delivered with CS3. Let’s start setting up a simple component…
Setting up our first component
- Create an empty Flash ActionScript 3 document. Save it in an empty folder as CustomComponents.fla
-
Add the following class path to the document’s settings:
$(AppConfig)/Component Source/ActionScript 3.0/User Interface
This is where the core component code resides (in particular fl.core.UIComponent)
- Create an ActionScript class for your component. Save it as MyComponent.as in the same folder as the CustomComponents.fla file.The class should extend fl.core.UIComponent, so the opening lines of your component class should look something like this:
- Create a MovieClip symbol in the library, and change its name to “Avatar” (users of the V2 architecture are more likely to remember this as the asset formerly know as BoundingBox, and functionally, the Avatar fulfills a similar role). Enter edit mode on that symbol, and on frame 1 (the only frame) draw a rectangle with x and y coordinates of 0 and no fill. It’s probably best to use a hairline stroke, as when this symbol is used later, it is likely to be scaled, which will do odd things to non-hairline strokes.
- Create a MovieClip symbol in the library, and give it the same name as the class you defined above (e.g. MyComponent)
- Edit this symbol, and rename layer 1 to Avatar, and drag in the Avatar symbol from the library to x and y coordinates of 0. Ensure that this is the only symbol instance on frame 1 of your component MovieClip. UIComponent will use this instance to set its default width and height, and then remove it from the display list immediately. It only does this for the DisplayObject at index 0, so we don’t want any other display objects on this frame.
- Create a new layer called “skins”, and create an empty key-frame on frame 2. This is where we will be placing subsequent symbols from the library that represent the various skins for our component.
- Create a new MovieClip symbol in the library and call it MyComponentSkin1 (this time, in the linkage properties, check “export for AS” and “export in 1st frame”, and enable 9-slicing). Draw something pretty on frame 1.
- Edit frame 2 layer “skins” of MyComponent, and drag MyComponentSkin1 from the library into this frame. Don’t worry about positioning it… it’s never used at runtime; this is the view that will open when the user double clicks the component. When the component gets more complicated, it might be worth adding a guide layer to this frame with some labels for the various skin assets.
-
Right click MyComponent in the library and choose Linkage… In the following dialog box, provide the following details:
Class: MyComponent
Base class: flash.display.MovieClip
Check “Export for ActionScript”
Check “Export in first frame”
-
Right click MyComponent in the library and choose Component Definition… In the following dialog box, provide the following details:
Class: MyComponent
There are several other options on this panel that can be configured, but leave them (for now…)
What is a ComponentShim, and why do I need one?
Tracking down the ComponentShim
One of the more confusing aspects of the new FLA-based architecture is a compiled clip called ComponentShim. The documentation refers to it only once with the following rather cryptic line:
“The ComponentShim SWC is placed on Stage on Frame 2 in every User Interface component to make available the precompiled definitions.”
That’s all you get. A web search turns up even less. A quick search of the CS3 file system finds no .SWC file called ComponentShim. The only clue is a file called ComponentShim.fla, which has provided some insight into the purpose and creation of the ComponentShim.
If you pull any of the components supplied with CS3 out of the components panel into a new document, along with the component skins, one of the additional symbols that is imported into your library is a Compiled Clip called ComponentShim It is placed in a library folder called “_private”. An instance of ComponentShim can be found on frame 2 of all of the components supplied with CS3 (in User Interface.fla). A few questions immediately spring to mind… Why is it there? How is it made?
V2 architecture developers are probably familiar with compiled clips. These are non-editable MovieClips in the library that contain their own assets and code in a ready-compiled format. Indeed, in the not-so-distant past, when you dragged a V2 component from the components panel onto the stage, its symbol instance in the library was of type “compiled clip”. When they are used in a project, the contents of the compiled clip are built in to the resultant SWF, without any need to recompile the code that they contain. If classes in the precompiled code of a compiled clip are not used in a client project, then the byte code for those classes is not copied into the resulting SWF. It turns out that this behaviour is a great benefit to the FLA-based component architecture, and gets us out of some tricky issues.
Looking at component usage
When the end user drags a component (without a ComponentShim) into their project, a number of items are added to the library. These are the component item itself, and all the associated assets of the component. When the time comes for the user to publish their project, a problem arises… the component is derived from (in our case) the MyComponent.as code, which is in turn derived from UIComponent. However, in the end-user’s project, neither of these files is in the document’s class path (if you remember when setting up the component FLA, additional class paths needed to be added). When document is exported, Flash sees that MyComponent uses class MyComponent, but cannot find a definition for MyComponent. So, by default, it auto-generates its own version of the MyComponent class, a very simple subclass of MovieClip, with no other code and no reference to UIComponent. MyComponent doesn’t work, because it has no code, and ends up with the behavior of a basic MovieClip.
ComponentShim to the rescue
As a component developer, sometimes we don’t want to supply our component code to the end user. Even if we do, we don’t want them to jump through the additional hoop of setting up their class path to include the MyComponent code and the UIComponent code. This is where the ComponentShim comes to the rescue. If all the required code is included in a precompiled format in the component’s assets, it means that we don’t have to supply the component code, nor is there a requirement for the end-user to set-up their class path to include the necessary code. The ComponentShim is a precompiled clip containing all the classes that are used by components in the component .FLA, but with none of the assets. With the ComponentShim included as an asset, this code is already available and no further action is required by the end user to get this code working with the component they are trying to use. An added benefit is that when the end-user compiles their project, they don’t need to recompile the component code every time they export.
How to make a ComponentShim
- Create a new ActionScript3 Flash document.
- Set up the class paths for the document with exactly the same paths as in the component .FLA we created above
- For each component in the original component .FLA, create a MovieClip symbol in the library. In the linkage settings set its class to the class used by the component and ensure that “Export for ActionScript” and “Export in first frame” are checked.
- Add one more symbol to the library, called “ComponentShim source”. (I have found that it is useful to put some sort of graphic/text on frame 1 of this symbol, something Adobe does not do. With no graphical presence, when we use it later it is easy to lose the instance on the stage, as it completely disappears. Once again make sure that “Export for ActionScript” and “Export in first frame” are checked in the linkage properties of the symbol. Associate it with some non-existent class, so that Flash auto generates a class for it. I’d suggest then class name “ComponentShim”, but technically the choice of name is completely irrelevant, as long as there is no collision with other class names.
- Right click the ComponentShim symbol in the library, and choose “Convert to Compiled Clip”.
- If all the classes compile correctly, then a new compiled-clip symbol will be created called “ComponentShim source SWF”. Select the symbol in the library and rename it to “ComponentShim”. This is now in essence a compiled repository of all the component code, with none of the associated assets.
- Drag the “ComponentShim” symbol from its library into your component .FLA library.
- For each component in your FLA-based component library, drag an instance of ComponentShim from the library on to frame 2 of the component. If you are working through this walkthrough, then currently the only component in the library is “MyComponent”, so you will need to do this only once.
A working component. Kind of…
By this point, we should now have a working component. If we copy the component .FLA into the correct folder [ $(AppConfig)/ Components ] and restart Flash, then we will see a new branch in the Components Panel tree view labeled with the name of the .FLA, and with MyComponent as a sub-item. However, when this is dragged onto the stage, we do not see a rendition of our beautifully designed component. All we see is its bounding box (the Avatar instance we dropped on frame 1 of our component). It behaves in every way like a normal MovieClip that has been associated with a class. It has no live preview. Nowhere in the process above did we precompile a working version of our component for use as a live preview. This is one area where V2 SWC based components were better, because the generation of a live preview was done automatically. For FLA based components, it is necessary to create a live preview by hand.
Finishing the job
Creating a live preview SWF for the component
Hidden in the documentation is a new class called fl.livepreview.LivePreviewParent. In the linked document, two different methods are outlined for creating a live preview SWF. One of them is a hack and involves creating a SWC file from your component, renaming the SWC file so it has a ZIP extension, and extracting the SWF file that it contains.
Unless I have missed something, I think CS3 is a let down on this front. How easy would it have been to add new option somewhere near “Export SWC file…” that exported only the live preview SWF automatically? It could even automatically take care of hooking it up to the component.
In order to gain an understanding of what a live preview SWF is, I worked through the second (9 step) method for creating a live preview SWF. The steps for doing this are copied verbatim from the fl.livepreview.LivePreviewParent documentation:
- Create a new Flash document.
- Set its document class to fl.livepreview.LivePreviewParent.
- Drag your component to the Stage and position it to x and y coordinates of 0.
- Check to ensure that the component parameters remain at their default settings. This should be the case if you drag the component from the Library panel or from the Components panel.
- Select Modify > Document from the main menu and, for the Match option, click Contents.
- Click OK.
- Publish the file to see the resulting SWF file as a custom live preview SWF file.
- Right-click the asset in the Library panel and select Component Definition from the context menu.
- The Component Definition dialog box allows you to specify a custom live preview SWF file for a component.
Steps 8 and 9 here are slightly misleading here, as it is not made clear that you should be operating back in your original document’s (CustomComponents.fla) library, not the library of the newly created document.
A fully working FLA-based component
At this point, you can save CustomComponents.fla and close Flash. Copy CustomComponents.fla to $(AppConfig)/Components and reopen Flash. Create a new ActionScript3 Flash file and open the components panel. You will see the CustomComponents entry, and within it, the new MyComponent. When this is dragged to the stage, it works just as a component should. Job done.
Automating the process
Automation helps prevent strain injuries…
The whole process and workflow of making a component is quite long and awkward, but offers a much greater reward in end than the V2 process. Most of the steps are set-piece and would be well suited for automation via the Flash JavaScript API (JSFL). I thought I would see how far I could get. It proved considerably more complicated than I expected it to be. Somewhat annoyingly, the JavaScript API lacks any kind of functionality to make changes to the Component Definition panel. This makes complete automation impossible. I find it strange that this area of JSFL has not been improved upon in CS3, especially as the component creation workflow has so many steps.
FLA_Component_Helper.jsfl
When do I use it?
The script is designed to be used for initial use immediately after setting up the component FLA for the first time. In the walkthrough above, this would be at the end of the “Setting up our first component” section. It eliminates the need to perform all but a very small portion of the rest of the process. Deficiencies in the Flash JavaScript API mean it is not possible to completely automate the process.
What does it do?
The process will create and delete an additional FLA file in the same folder as the current document. It uses this document to generate a component shim for all components that are found in the current document’s library. The shim has no graphical representation. When the shim this has been created, an extra layer is created on the timeline of each component discovered in the component FLA document. An empty keyframe is created on frame 2 on this new layer. The newly created shim is added to this frame. Additionally, the script automates the creation of live preview SWF files, and saves them in the same folder of the component FLA. A live preview SWF is created for each component that is discovered, with an automatically generated filename ComponentName_live_preview.swf. Subsequent runs of the script will ensure that the old shim is removed prior to building and adding an updated one, but it is important not to rename the layer (labeled “autogenerated_shim_layer”) upon which the shim is placed. As Flash CS3 does not allow manipulation of the “Component Definition” panel via JSFL, the last remaining step must be done manually. This involves opening the Component Definition panel for each component in the library, and pressing the “Set…” button next to the “Live Preview” entry. From there, ensure that “Live preview with .swf file embedded in .fla file” is selected, and navigate to the corresponding live preview SWF file that was just created. Once this has been set once, it will only be necessary to hit the “Update” button to refresh the SWF image that gets stored in the FLA file.
Warning
The script will only work on a PC, due to file path issues that I do not know how to address. I don’t know how OSX file paths work, and the script will surely break. The script saves the current document when it starts. It also makes use of temporary files, which it deletes with JSFL command FLfile.remove. While I am confident it has been used correctly, please ensure your project is backed-up before you first run the script. If the script fails, no attempt is made to clean up the temporary files, but they will not interfere with subsequent runs of the script.
How do I use it?
Simply save the script to your hard drive and when you have prepared you component FLA (as described above), go to Commands -> Run Command… and open the script. Once it has completed, don’t forget to update the Component Definition for each component, as described above.
I am facing a problem with component development where my component contain other components. After pasting my fla file to Components folder, Flash shows other components which are used in my component. I tried your workaround but it doesn’t works for me. Could you please explain a bit on how not to display the default components which are used in my component.
What I have done:
I created a Component Shim for my component by
1.creating a blank MovieClip
2.naming its class as MyComponentShim
3.then converted it to Compiled clip
4. Rename as MyComponentShim
5. Replace default Component Shim with the one I created above and then compile my component again.
6. Paste it to Components Folder.
Please help me with this. I don’t want to display the default components used by my Component.
Looking forward to your response.
–
Chetan Sachdev
very descriptive. Thank you.
Thank you very much. This article (together with a few others and alot of digging around) helped me understand the components.
I have written a small piece on the same subject, as it seems alot of people are still having problems with this.
http://redbjarne.wordpress.com/actionscript-3-0-custom-components-from-hell/