In Flash Professional CS5, when you use TLF text in your SWF, by default we do some tricks behind the scenes to preload TLF as a Runtime Shared Library (RSL) in a way that does not require you, the content author, to write any ActionScript to manage the preloading at all. However, if you are setting up your FLA with preloading in mind, where you use the first one or more frames as a preloading animation and then have ActionScript to move past this section once the loading is complete, then you should take advantage of the custom preloader loop feature which will work with your preloader animation and will only require a tiny bit of extra ActionScript. And in fact if you do not use the custom preloader loop feature, then your preloader animation will never be displayed.

General Preloading Example

Let’s walk through an example first and then I’ll go into some more explanantion of what is really going on. Flash CS5 has a sample template installed called Preloader for SWF. You can create a new FLA from this template by selecting the File -> New… menu item, then selecting the Templates tab, selecting the Sample Files category and finally select the Preloader for SWF template and click OK. This template is set up with some loading text on frame one along with some ActionScript on frame one to track the loading and display a percentage to the user until 100% is loaded, at which point it will go to frame two which has the real content.

To see how this preloader template is intended to work, select frame two of the Content layer in the Timeline panel and import some image. Next select the Control -> Test Movie menu item and you should see it go to your content on frame two seemingly instantly, which is because of course it did not have to download. If you keep the test movie window open and select View -> Simulate Download, you should now see the LOADING text and the download percentage display.

Adding TLF Breaks the Preloading Animation

Now try this: move the image off to the side, so it isn’t covering the “Large content here” text. Select that text and in the Properties panel change the combobox at the top from Classic Text to TLF Text. Now try the same steps again. First, when you test movie, you may get a warning dialog like this:

Your content will not stream. Runtime Shared Library (RSL) preloading will require all of your content to download before the first frame will play.  To prevent this you can change the Runtime Shared Library Settings in the Advanced ActionScript 3.0 Settings dialog which can be raised from the Publish Settings dialog.  The Runtime Shared Libraries being preloaded are:  textLayout_1.0.0.595.swz for TLF Text

So let’s talk briefly about what this dialog is saying. A preloader animation loop at the beginning of your timeline works in Flash because the player will start playing frames as soon as they are downloaded. This is what this dialog’s text means by “streaming”. So your preloader code and animation defined in frame one starts running as soon as all of frame one has downloaded, and while the user waits for the rest of your SWF to download, the preloader animation will run. However, the tricks we use to preload the TLF RSL before your content runs defeat this strategy. They require your entire SWF to download completely before frame one can be run. This is why it is so important to take advantage of the custom preloader loop which preserves your ability to stream your SWF and allows you complete control over the preloading experience.

Back to our example: if you keep the test movie window open this time and select simulate download, you will see a completely different preloading animation which is a line of five white circles that show and hide. So you might be wondering, what in the heck happened to my loading animation? As discussed in the previous paragraph, it is still there, but the preloading mechanism which we use to load the TLF RSL is taking precedence. It goes first, and it runs until your entire SWF content has loaded, which means that your preloading animation runs, but in a similar situation to how it runs in test movie mode without simulate download selected, which means it is dismissed instantaneously.

How to Use the Custom Preloader Loop Feature

You can take back control of your preloading by editing the preloader method in the Advanced ActionScript 3.0 Settings dialog. Raise this dialog by clicking on the Edit… button for ActionScript Settings in the Properties panel. If you do not see this button, click on the stage to select nothing so that the Document properties are displayed in the Properties panel. Once this dialog is raised, there are two important settings you need to change:

  • In the Library path tab, change the Preloader method from Preloader SWF to Custom preloader loop.
  • Near the top, change Export classes frame near the top from 1 to 2.

Your dialog should look like this when you are done:

Advanced ActionScript 3.0 Settings dialog

Now it is time to add some ActionScript to frame one of the Actions layer. I’ll walk through the details later, but for now the code in that frame will look like this, so you can just copy and replace the whole block:

import fl.events.RSLEvent;

stop();

var swfComplete:Boolean = false;
var rslComplete:Boolean = false;

this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
this.loaderInfo.addEventListener(Event.COMPLETE, onComplete);
this.addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

function onLoading(evt:ProgressEvent):void {
	var loaded:Number = evt.bytesLoaded / evt.bytesTotal; 
	percent_txt.text = (loaded*100).toFixed(0) + "%";
};

function onComplete(event:Event):void { 
	this.loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onLoading);
	this.loaderInfo.removeEventListener(Event.COMPLETE, onComplete);
	swfComplete = true;
	if (rslComplete && swfComplete) {
		gotoAndStop(2); 
	}
};

function onRSLComplete(e:RSLEvent):void
{
	this.removeEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);
	rslComplete = true;
	if (rslComplete && swfComplete) {
		gotoAndStop(2); 
	}
}

Now try test movie and simulate download again, and you will find your loading animation working and restored. One thing you might notice when you simulate download is that you get a white screen for much longer than you did without TLF. This is because when you specify the export classes frame as frame two, what this really means is export all classes that are not required on frame one in frame two. There is quite a bit of ActionScript code that still needs to be on frame one, and you see the blank, white screen while you wait for this to download.

On a tangent, SWF size can be a concern with TLF. Even if the image I added to the FLA earlier, my published SWF is showing up as 59.4KB in the SWF History section of the Properties panel when I use TLF with a custom preloader loop. The good news is this is a bit smaller than the 61.2KB I get if I use the default Preloader SWF preloader settings, but the bad news is that it is much bigger than the 9.4KB when I use classic text. But on the other hand if I change the Default linkage setting in the Advanced ActionScript 3.0 Settings dialog to Merged into code, my SWF size balloons up to 187.4KB! So the RSL approach for TLF is still winning you quite a bit, and because it is deployed as a signed, cacheable RSL, or a SWZ file, by default, each user should only have to download the RSL once for every SWF that they ever run that uses it, which means with luck your SWF will not be the one that takes the download hit for the RSL.

How does it work?

Preloader Method: Custom Preloader Loop

So let’s talk about what you’ve done with the changes you’ve made. First I’ll explain the preloader method change to custom preloader loop. The preloader SWF method exports your SWF basically unchanged, and then wraps that SWF in another automatically generated SWF. We take advantage of the DefineBinaryData swf tag and the Loader.loadBytes API to make this work. However, when you select custom preloader loop, instead we inject the RSL preloader code directly into your SWF. While this has many benefits, the reason we cannot do this by default is that since you retain complete control over the timeline, you are required to take all the additional steps.

Export Classes Frame

The first additional step required is the change to the export classes frame. While in this example we changed it to frame two, note that in general it needs to be changed to the first frame after your preloading animation is complete. In other words, you cannot play the frame specified in the export classes frame until you have verified that all RSLs are done loading.

It is educational to see what happens if you leave the export classes frame set to one. So try going back into the Advanced ActionScript 3.0 Settings dialog and switch the 2 back to a 1 and test movie. The first thing you will notice is some errors in the output panel:

VerifyError: Error #1014: Class flashx.textLayout.container::ContainerController could not be found.

ReferenceError: Error #1065: Variable ComponentShim is not defined.

ReferenceError: Error #1065: Variable Font_5 is not defined.

ReferenceError: Error #1065: Variable MainTimeline is not defined.

If you go to the compiler errors panel, you will see a warning that actually explains your situation:

Warning: 5010: Use of a custom preloader loop with the RSL for TLF Text requires that the export classes frame be set after the end of the preloader loop to avoid VerifyErrors.

Essentially what has happened is we have forced some classes into frame two that depend on the classes defined within the RSL. If you attempt to load these classes by playing frame two before the RSL is finished loading, then bad things happen.

On a side note, while it is not really recommended to put any TLF on stage in your preloader animation, believe it or not bad things do not happen if you put some TLF text on frame one. Well not especially bad, anyways. Try this: restore your export classes frame back to 2, create a new layer on your timeline put some TLF text in frame one that new layer, so that it should show up on both frame one and two at runtime. If you test movie, you will not get any errors and your text will show up correctly. However, if you try a simulate download to see what it looks like, you should not see the TLF text display at all on frame one, during the preloading animation, but it will appear on frame two. We have smarts behind the scenes that fails as gracefully as possible and makes the right thing happen.

ActionScript

Finally, let’s dig into the ActionScript itself. Let’s look at what has been added to the original preloader code:

import fl.events.RSLEvent;

This is simply an import for the RSLEvent type. Many classes are imported for you automatically when writing ActionScript on frames in Flash Professional, but not the RSLEvent class.

var swfComplete:Boolean = false;
var rslComplete:Boolean = false;

Your script could be simpler when you were only waiting for one event to happen before proceding to frame two, but now that you need to wait for two events, you must use Boolean variables to track each of them separately.

this.addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

The RSL_LOAD_COMPLETE event is a new event that is dispatched by the main timeline when all RSLs have finished downloading. In this case the only RSL is for TLF, but you would still only need to listen for this one event no matter how many RSLs were downloading.

	swfComplete = true;
	if (rslComplete && swfComplete) {
		gotoAndStop(2); 
	}

This code was added to the onComplete function. It marks swfComplete = true to indicate that the swf loading is finished, and then checks to ensure that rsl loading is complete before going to frame two.

function onRSLComplete(e:RSLEvent):void
{
	this.removeEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);
	rslComplete = true;
	if (rslComplete && swfComplete) {
		gotoAndStop(2); 
	}
}

This is the event listener function for the RSL_LOAD_COMPLETE event. The code is very similar to the code in the onComplete method, except for it sets the rslComplete Boolean to true.

Really pretty simple code. Not just one or two lines, but not too much more than is already required to make a preloader loop like this work.

16 Comments

  1. natalie says:

    Hi Jeff,

    Question for you. I am trying to use my own preloader animation and code in frame one of the main timeline. I have disabled the default preloader loop via the publish settings and set it to “merge into code”. However, my preloader (a simple percentage counter) takes a while to appear and shows up at around 80%. Is this b/c of the time it takes the player to download my AS for the preloader and the embedded text (using Classic text in the preloader)?

    Also, does the Flash dot, dot, dot preloader (they look like ellipses) only run when some preloader code is added? I don’t see the preloader on all of my CS5 projects, only on those that I have tried to add my own preloader as I did with CS4.

    Thanks!

  2. Szymon says:

    I’ve got simple preloader
    stop();

    addEventListener(Event.ENTER_FRAME,loaderF);

    function loaderF(e:Event):void {
    var toLoad:Number=loaderInfo.bytesTotal;
    var loaded:Number=loaderInfo.bytesLoaded;
    var total:Number=loaded/toLoad;
    if (loaded==toLoad) {
    removeEventListener(Event.ENTER_FRAME,loaderF);
    gotoAndStop(2);
    } else {
    preloader_mc.preloader_bar.scaleX=total;
    preloader_mc.total_bytes.text=toLoad+” total bytes”;
    }
    }
    on first frame and rest on second and i get this warning

    Warning: 5010: Use of a custom preloader loop with the RSL for TLF Text requires that the export classes frame be set after the end of the preloader loop to avoid VerifyErrors.

    According your tutorial i put TLF loader class on second frame too with tlf text .
    I was tryin i think all .
    Plz can u help me , with sending some source code how it should look?

    Thanks

  3. jeff says:

    @natalie, sorry took so long to approve your comment, i get SO many spam comments i get really lazy about reviewing them. If you select merged into code, this will give you problems like you describe because your custom preloader animation will not begin to display until after frame one has loaded completely. By selecting merged to code, you have merged all of the TLF code into the first frame of your SWF, so by the time your preloader animation appears, you have already loaded most of the SWF.

    Even with merged to code, you could change the setting for export classes in frame: to 2 as described in the article and this might make your preloader animation work better.

  4. jeff says:

    @szymon sorry for the delay in approving your comment! I hope my advice can still be helpful.

    make sure that you have changed the value in the Export classes in: text box to 2 in the Advanced ActionScript Settings dialog as described in the article. Once this is fixed you will still need to add code to your preloader code similar to the code in this article. The key is that before you go to frame 2, you must be sure that you have received the RSLEvent.RSL_LOAD_COMPLETE event, so you need to add a listener for that event which will set some variable to true, and then instead of just checking (loaded == toLoad), you would need to check (loaded == toLoad && rslLoadCompleted) or something like that.

  5. YL says:

    Hi, I tried your method; everything worked fine except one thing: My TLF text boxes now show only the default font. Embedding them in doesn’t seem to help. Is there anything I can do about that?

  6. derek says:

    Thank you for the breakdown involving custom preloading and RSL. I am getting a “, Line 1 Warning: 5011: Code exported in frame 1 directly depends on a definition in the RSL for TLF Text which may cause VerifyErrors due to the use of a custom preloader loop: fl.text.TLFRuntimeTabManager” in my Compiler Errors. I don’t have any TLF text in frame 1 though, so I’m confused as to why I’m getting this warning. Also, I’m pretty sure it has to do with the RSLEvent as it doesn’t seem to be imported. Is there another fl.events package that includes the RSLEvent class? I have the fl.events package (with code hinting) but the RSLEvent class does not show up.

  7. jeff says:

    @derek: yikes having that warning in there is a bug! ugly. I just played with a simple example and i saw the warning as well, but i didn’t see any actual runtime problems. If you are seeing the same, then you can actually safely ignore the warning.

    But if the warning is bothering you, there is a way to make it go away. You just need to edit an xml file. Under your Flash Pro install folder, browse to Common/Configuration/ActionScript 3.0/rsls and make a copy of the file textLayout_2.0.0.xml on your desktop. (Since you need admin priveleges to edit this file, it works better to copy it to somewhere that will not require the heightened priveleges to edit it, and then you can copy the edited version back). In the list of <dependent-class> tags, add a line like this:

    <dependent-class safelyDependsOnRSL=”true”>fl.text.TLFRuntimeTabManager</dependent-class>

    Once you copy the file back to the location under your Flash Pro install folder, you will need to quit and restart Flash Pro for the changes to take effect.

  8. jeff says:

    @YL i was able to reproduce this problem with the default font being used. The good news is that there is a simple work around. When your custom preloader loop completes, avoid having any TLF on the first frame that is played. The easiest i found to do this was to have my gotoAndPlay() go to a blank frame first, and then have the next frame have the real content on it.

  9. derek says:

    @jeff: The warning isn’t bugging me specifically, but it does print 3 times which seems odd. I’ve since implemented a spin-off of your example but I’m a little displeased with the way I had to go about setting up my FLA to preload the TLF RSL. The core issue was that if I had a Document class, I would not receive the RSLEvent.ON_COMPLETE within it. I was only able to capture the RSLEvent.ON_COMPLETE event when I had the code in the Actions panel. This is not the way I like to have projects set up (as I prefer to have a document class). Do have a clue as to why I was only able to capture the event if I listened for it in the Actions panel as opposed to my Document class? Hopefully you can shed some light here, thanks again for any help.

  10. derek says:

    @jeff: Also, I’m getting a “Warning: Ignoring ‘secure’ attribute in policy file from http://fpdownload.adobe.com/pub/swz/crossdomain.xml. The ‘secure’ attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.” when testing my SWF on my staging server. This prevents my SWF from executing properly, but upon hitting refresh in my browser the SWF works as expected (but I again see the warning output to my trace log (Vizzy Flash Tracer). So it is prevented from player correctly on the first go around, but on a refresh it plays. I’m pretty frustrated with TLF and RSL in general, but I have to use TLF to get the textual flexibility I need. Thanks again if you’re able to drop any knowledge, I’m seeing many other people have similar issues in forums and the like, but the only solution I see is to “merge with code” which is NOT an option as it insanely increases file size. Thanks again for any help!

  11. jeff says:

    @derek: i think probably the secure attribute is there so that the same crossdomain.xml file will work for both http and https connections. I wasn’t able to repro the warning issue you had immediately, but i do not have a debug browser player installed. It could be that only people with debug players installed are seeing this issue, which would at least mean that the majority of your audience would not see the problem, but i’m not sure.

  12. jeff says:

    @derek: re the cannot use a Document class and do a custom preloader. D’oh! This is a bug i didn’t even realize was there until you posted that. That is supposed to work. But you are correct, it doesn’t work in CS5 or CS5.5.

  13. DavidC says:

    So, I followed the instructions to the letter, and I’m not able to get the RSLEvent to fire at all, no matter what I do. However, like derek, any kind of timeline based solution is not really viable anyway since our whole workflow is based on a custom framework which makes heavy use of document classes for flas. We really need to find a way to integrate the TLF into our existing framework in order to accommodate Arabic-speaking clients, but we can’t really afford the extra bulk that the Merged into Code option creates. There MUST be some way to reproduce Flex’s handling of RSLs in general inside the Flash IDE. I wonder if the new RSLPreloader class might be of some use here? Any help would be greatly appreciated…it really seems a shame that the TLF offers so much great functionality, but is so incredibly difficult to use in the real world.

  14. YL says:

    Hi again. I tried to new a ContainerController somewhere in the code to use the SizeTextToContainerUtil class (http://aaronhardy.com/flex/size-text-to-container/), but it didn’t work. I suspsect the same would apply to all classes under flashx.textLayout.

    This works fine as long as a preloader SWF is used as the preloading method, but that certainly is not what I would have wanted. If I use a custom preloader loop, Flash warns with a 5011 message, and when I run the SWF file, the 1014 VerifyError it warns about would show up, saying that the ContainerController class cannot be found.

    I ended up ditching RSL and changing to merge into code, and the files did compile correctly. It didn’t help in my particular case, since the class I used is problematic on its own, but that’s another tale.

  15. Gold Price says:

    What a great tutorial. I deeply, deeply appreciate your plain language finesse. I’m building a preloader based on your instructions, and I’m running into the issue you point out at the very bottom regarding “Export for Actionscript.” I have used an FLVplayback component, some button components, and an embedded font. When I follow your advice to change the Export in Frame number under Publish Settings, my SWF gets unhappy. If I change the export frame from 1 to 2, suddenly none of those components work, possibly because my preloader scene contains no frame 2? If I leave the setting on frame 1, my preloader doesn’t seem to begin counting until frame 30 or so of my 100-frame preloader animation, possibly because Flash is busy loading the component items? Can I specify “load the component stuff in frame 1 of the scene that contains my actual content”? The Settings dialogue seems to be dummy-proofed to accept only numerals, so I’m not sure how to point it toward my second scene. Happy to send my FLA if you care to see my setup.

  16. jeff says:

    Sorry i just saw and approved your comment, Gold. I get so many spam comments on these old posts and i don’t get around to filtering through them for ages and i feel bad when a legitimate comment, esp with a question, gets forgotten. If you want to push back your class loading to later in the swf to be able to do preloading, you cannot really use any components or any of that stuff until after your preloader animation is over. If you need to push into a later scene, i think you would just add up all the frames across scenes (so if you first scene had thirty frames, and you wanted to export AS into the first frame of scene 2, you would put 31 for export frame). I know you have probably moved on and figured this out by now as it has been many weeks, but let me know if you are still struggling with this and i could try to help.