Hi Marcelo,

In Arp 3, this is going to be a documented use case and part of the 
framework but here's a general outline of how I implemented this in our 
last Flex project. I'm going to cut/paste code from there so you may 
need to tweak slightly to get it to work on your project but I'm sure 
you'll get the general idea.

The following should go either into your Application form (bad) or into 
a base class that your Application form extends. In Arp 3, it will be in 
org.osflash.arp.Application:

    // Declare the project package (used by registerScreen)
    // (Change this to reflect the package your app is in)
    private var mProjectPackage:String = "com.ariaware.bluek";

    // List of screens
    private var mScreenLoaders:Array;
   
    // List of already-loaded external MXML files
    private var mLoadedScreens:Object;
  
    //////////////////////////////////////////////////////////////////////
    //
    // Method: registerScreen()
    //
    // Registers an external screen with its Controller so that the
    // Controller can listen for System Events on the screen and
    // map them to Commands.
    //
    // Also calls a handler on the Application form so that it can
    // register to listen for View Events.
    //
    //////////////////////////////////////////////////////////////////////
    public function registerScreen ( screenName:String, screenRef:Object )
    {
        Log.info ("Registering screen: " + screenName);
   
        //
        // Register the screen with its Controller
        //
        var ControllerClass = findControllerClass( screenName );

        // Remove the controller if it has already been created
        // since if we go back to a screen, the screen refuses
        // to display correctly unless this is done.
        delete ControllerClass["inst"];
                       
        var screenController:Object = ControllerClass.getInstance();
        screenController.registerScreen ( screenRef );
               
        //
        // Call handler on Application form. If you want to listen for
        // View Events on the external screen, that's the place to do
        // it. The handler is named onRegisterScreenameScreen
        // (eg. onRegisterLoginScreen.)
        //
       
        var localHandler:Function = this [ "onRegister" + screenName + 
"Screen" ];
               
        localHandler.apply ( this, [ { target: screenRef } ] );
    }
   
    //////////////////////////////////////////////////////////////////////
    //
    // Method: unRegisterScreen()
    //
    // Removes the controller for the screen so that the screen can be
    // re-created successfully in the future.
    //
    //////////////////////////////////////////////////////////////////////
    public function unRegisterScreen ( screenName:String, screenRef:Object )
    {
        Log.info ("Un-registering screen: " + screenName);
   
        var ControllerClass:Object = findControllerClass( screenName );
        var screenController:Object = ControllerClass.getInstance();
       
        // Remove the controller since the screen is being removed -
        // this allows us to re-open popup windows without issue.
        //screenController.unRegisterScreen ( screenRef );
        delete ControllerClass["inst"];
               
        var localHandler:Function = this [ "onUnRegister" + screenName + 
"Screen" ];
        localHandler.apply ( this, [ { target: screenRef } ] );
    }

    //////////////////////////////////////////////////////////////////////
    //
    // Group: Private methods
    //
    //////////////////////////////////////////////////////////////////////

    private function findControllerClass( screenName:String ):Object
    {
        //
        // The package string must be declared in the projectPackage 
property.
        // It can contain any number of packages. However, the 
Controller class
        // *must* be in a package called "control"
        //
        var packageExploded:Array = mProjectPackage.split(".");
        var numPackages:Number = packageExploded.length;
        var packageRef:Object = _global;
        for ( var i:Number = 0; i < numPackages; i++ )
        {
            packageRef = packageRef [ packageExploded [ i ] ];
        }
        return packageRef["control"][ screenName + "Controller" ];
    }

In this app, I used a method called showScreen that manages 
navigation/loading of screens. Here it is, below -- uncleaned, sorry :) 
Note the use of a naming convention to map screens to their individual 
Loaders. We found that having multiple Loaders (one for each screen) 
makes the app much more responsive as we can cache already-loaded 
screens instead of having to reload it each-time. This is especially 
true due to the initialization delays in Flex. I'd recommend this route 
for a real-world app of any real size. Again, the code below is for Flex 
but will work in Flash with slight tweaking. Remember to use shared 
libraries when working with external forms to cut down your app size 
considerably.

    //////////////////////////////////////////////////////////////////////
    //
    // Method: showScreen()
    //
    // Display screen by name, loading it in first if necessary
    //
    /////////////////////////////////////////////////////////////////////
    private function showScreen ( screenName:String ):Void
    {
        // Assume that the item in the navigation menu that was
        // clicked on has a .mxml file named the same as the label
        var fileName:String = screenName + ".mxml.swf";

        // Since we're going to a "swf deploy" model now, we'll
        // load the .swfs directly, as opposed to the .mxml
        //var fileName:String = screenName + ".swf";

        // Reference to the Loader instance for this screen
        var screenLoader:Loader = this [ screenName + "Loader" ];
       
        // Log.info ( "File name: " + fileName );
        // Log.info ( "screenLoader: " + screenLoader );

        // Set the requested screen loader visible and hide the others
        var numScreens:Number = mScreenLoaders.length;

        for ( var i:Number = 0; i < numScreens; i++ )
        {
            // Log.debug ( i );
            var currentScreenLoader:Loader = mScreenLoaders [ i ];
           
            // Log.debug ( currentScreenLoader );
           
            currentScreenLoader.visible = ( currentScreenLoader == 
screenLoader );

            // Call the show method. Adding a listener on the form itself
            // for the show event doesn't get triggered for some reason.
            currentScreenLoader.content.show();
           
            // Log.info ( "Setting " + currentScreenLoader + " visible 
to " + ( currentScreenLoader == screenLoader ));        
        }
       
        //
        // Optimization: Check if this screen has already been loaded. 
If it has, just
        // display it (without initialization -- this will knock 5-10 
secs off
        // navigation to and fro screens.)
        //
        if ( mLoadedScreens [ screenName ] == undefined )
        {   
            Log.info ( "First time, loading " + screenName + "... " );
           
            // First time: Load in the external SWF
            screenLoader.load ( fileName );
       
            // Add the external swf to list of laoded SWFs (we assume
            // that once load has started, it will complete.)
            mLoadedScreens [ screenName ] = true;
        }  
    }


Then, in each of your external forms, you need to register the screen 
with the main application when it loads so that its controller will be 
initialized. Thus, each of your external forms will have its own 
controller. eg. (for Flash, do this on onLoad()). The registerScreen() 
method takes the name of the screen being loaded in as the first 
parameter. It uses this as a naming convention to call a method called 
onRegister<ScreenName>Screen. In the example below, for example, after 
the Contacts screen has been registered with the main application, Arp 
will try to call a method called onRegisterContactsScreen() on the 
Application form. This is where you can add listeners to listen for View 
events on the external form.

    //////////////////////////////////////////////////////////////////////
    //
    // Method: onChildrenCreated()
    //
    // Gets called automatically on childrenCreated by base FlexApplication
    //
    // 1. Register screen with the root application.
    //
    // 2. Interact with child components and forms: Add event listeners,
    // initialize them or perform initial validation, etc.
    //
    /////////////////////////////////////////////////////////////////////
    private function onChildrenCreated ():Void
    {
        // Register this screen with the root application.
        // If the screen is being tested by itself, the call will 
silently fail
        // without affecting the screen itself.
        mx.core.Application.application.registerScreen ( "Contacts", this );

       // Other stuff...
    }

Hope this helps. I'm working on Arp 3 at the moment and the handling of 
external forms is just one of the new features. It's going to be quite a 
revolutionary update :)

Take care,
Aral

Marcelo de Moraes Serpa wrote:

>What would be the best method to develop a multi-movie based application 
>on ARP? With multi-movie I mean that there would be a shell movie (the 
>application form) that would load the "children" forms at runtime. I 
>thought in doing this way:
>
>    * The Application Form would define a loadForm() method that
>      implements code that manages the transition effects and loads the
>      external SWF containing the child form and this would somehow also
>      show the loading progress to the user (maybe using the
>      MovieClipLoader class). There would also be a *placeholder clip
>      *on the Application Form“s layout that would be the target of the
>      loadMovie()/MovieClipLoader.loadClip() method.
>
>What do you think?
>
>Thanks,
>
>Marcelo.
>

_______________________________________________
osflash mailing list
[email protected]
http://osflash.org/mailman/listinfo/osflash_osflash.org

Reply via email to