Saturday, February 5, 2011

AS3 Class ResourceLoader

This class is useful for a couple of reasons.
  • It works just like the SWFLoader class, except that the content property is bindable.

  • You can play loaded movieclips using spark.effects.Animate and SimpleMotionPath. Animating property currentFrame from 0 to -1 for example.

  • You can load assets from resource bundles at runtime. Using properties key and bundle.


mitch/components/ResourceLoader.as

package mitch.components
{
import flash.display.DisplayObject;

import flash.display.MovieClip;
import flash.events.Event;

import mx.controls.SWFLoader;


/**
* <p>The ResourceLoader class is useful for
* loading assets from resource bundles at runtime.
* Set properties <code>key</code> and <code>bundle</code> so they
* correspond to an existing entry in a resource bundle.
* Don't forget to embed, or load, the resource bundle.</p>
*
* Unlike the SWFLoader class, property <code>content</code> of this class
* is bindable.</p>

*
* <p>If the loaded asset is a MovieClip, property <code>clip</code>
* will be set to that MovieClip. And property <code>currentFrame</code>
* can be used to animate the MovieClip.</p>

*
* @author Mitch
*
*/
public class ResourceLoader extends SWFLoader
{
/**
* Constructor.
*
*/
public function ResourceLoader()

{
 super();

 //dispatched by super-class
 addEventListener("sourceChanged", sourceChangedHandler);

}




//--------------------------------------------------------------
//
// Public Properties
//
//--------------------------------------------------------------


//------------------------------
// clip
//------------------------------

/**@private */
private var _clip:MovieClip;


[Bindable("contentChanged")]
/**
* Returns the object at property <code>content</code> as MovieClip.
*/
public function get clip():MovieClip { return _clip; }


//------------------------------
// content
//------------------------------

[Bindable("contentChanged")]
/**@inheritDoc */
public override function get content():DisplayObject {

 return super.content;
}

//------------------------------
// currentFrame
//------------------------------


/**@private */
private var _currentFrame:int = 0;

[Bindable("currentFrameChanged")]

/**
* Defines the current frame of the MovieClip at property <code>clip</code>.
*/
public function get currentFrame():int { return _currentFrame; }

/**@private */
public function set currentFrame(value:int):void {

 if(value != _currentFrame) {
  _currentFrame = value;

  if(clip) {

   while(_currentFrame > clip.totalFrames - 1) {
    _currentFrame -= clip.totalFrames;

   }
   while(_currentFrame < 0) {
    _currentFrame += clip.totalFrames;

   }
   clip.gotoAndStop(value);
  }
  dispatchEvent(new Event("currentFrameChanged"));

 }
}

//------------------------------
// totalFrames
//------------------------------

[Bindable("contentChanged")]

/**
* Returns the total amount of frames at property <code>clip</code>.
*/
public function get totalFrames():int { return clip?clip.totalFrames:0; }





//------------------------------
// bundle
//------------------------------

/**@private */
private var _bundle:String;


[Bindable("resourceChanged")]
/**
* Defines the name of the bundle to retrieve the resource from.
* @see #key key
*/
public function get bundle():String { return _bundle; }

/**@private */
public function set bundle(value:String):void {

 _bundle = value;
 addEventListener(Event.ENTER_FRAME, validateResource);
}


//------------------------------
// key
//------------------------------

/**@private */
private var _key:String;


[Bindable("resourceChanged")]
/**
* Defines the key of the resource
* in the bundle defined at <code>bundle</code>.
* @see #bundle bundle
*/
public function get key():String { return _key; }

/**@private */
public function set key(value:String):void {

 _key = value;
 addEventListener(Event.ENTER_FRAME, validateResource);
}


/**
* @private
* Event handler for enterFrame events.
* This handler is called only once, if properties key and bundle
* are altered in the same frame.
*/
private function validateResource(event:Event=null):void

{
 removeEventListener(Event.ENTER_FRAME, validateResource);
 updateResource();
 dispatchEvent(new Event("resourceChanged"));

}

/**
* Updates property <code>source</code> using the ResourceManager.
* <p>This method is called internally after properties
* <code>key</code> and/or <code>bundle</code> change.</p>

*/
protected function updateResource():void
{
 source = resourceManager.getClass(bundle, key);

}


//--------------------------------------------------------------
//
// Protected Methods
//
//--------------------------------------------------------------


//------------------------------
// contentChanged()
//------------------------------

/**
* Updates property <code>clip</code> and dispatches the binding event
* of type <code>contentChanged</code>.
* This method is called internally when property <code>content</code> changed.
* @param oldContent The old value of property <code>content</code>.
* @param newContent The new value of property <code>content</code>.
*/

protected function contentChanged(oldContent:DisplayObject, newContent:DisplayObject):void

{
 if(newContent is MovieClip) {
  _clip = newContent as MovieClip;

 }
 else {
  _clip = null;
 }

 dispatchEvent(new Event("contentChanged"));

}





//--------------------------------------------------------------
//
// Private Functions
//
//--------------------------------------------------------------


/**@private */
private var oldContent:DisplayObject;

/**
* @private
* Event handler for "sourceChanged"

*/
private function sourceChangedHandler(event:Event):void
{

 if(!source) {
  removeEventListener(Event.ENTER_FRAME, contentChangedHandler);
  removeEventListener(Event.COMPLETE, completeHandler);

 }
 addEventListener(Event.ENTER_FRAME, contentChangedHandler);
 addEventListener(Event.COMPLETE, completeHandler);

}

/**
* @private
* Event handler for "enterFrame" after "sourceChanged"
*/
private function contentChangedHandler(event:Event):void

{
 removeEventListener(event.type, contentChangedHandler);
 if(content) {

  //loaded quick
  removeEventListener(Event.COMPLETE, completeHandler);
  contentChanged(oldContent, content);

 }
 oldContent = content;
}

/**
* @private
* Event handler for "complete" after "sourceChanged" (and "enterFrame")
*/

private function completeHandler(event:Event):void
{
 //needed to load over time

 removeEventListener(Event.COMPLETE, completeHandler);
 removeEventListener(event.type, contentChangedHandler);//just in case

 contentChanged(oldContent, content);
}


}
}

No comments:

Post a Comment