Creating a component by just extending sprite and adding elements used to pop up timing issues which is very common in Fash if the architecture is not right.
I have tried to build a core component class architecture; which can be extended for developing any form of liquid UIs and components. This will eliminate the timing issues and will work flawlessly with high performance.
/**
* Component.as
* Flash Player 9.0.28.0
*/
package com.core
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
public class Component extends Sprite
{
// ------------------------------------------
// PROPERTIES
// isSuspended starts as true as the component is off stage
protected var _isSuspended:Boolean = true;
protected var _width:Number = 0;
protected var _height:Number = 0;
public static const DRAW:String = "draw";
/**
* Constructor
*/
public function Component():void
{
super();
if (stage) {
resume();
}else {
init();
}
}
///////////////////////////////////
// PROTECTED METHODS
///////////////////////////////////
protected function init():void
{
// concrete classes that override this function should call super.init()
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
// initialise component here.
// no need to call draw() as it will be called when component is added to the stage.
}
/**
* Overriden in subclasses to create child display objects.
*/
protected function createChildren():void
{
// defining component elements
}
protected function invalidate():void
{
if(!hasEventListener(Event.ENTER_FRAME))
addEventListener(Event.ENTER_FRAME, onInvalidate, false, 0, true);
}
protected function draw():void
{
// concrete classes should override this function
// redraw component state
dispatchEvent(new Event(Component.DRAW));
}
///////////////////////////////////
// PUBLIC METHODS
///////////////////////////////////
public function destroy():void
{
// concrete classes that override this function should call super.destroy()
// remove all listeners here
suspend();
removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
}
public function suspend():void
{
// concrete classes that override this function should call super.suspend()
// suspend all processes
removeEventListener(Event.ENTER_FRAME, onInvalidate);
this._isSuspended = true;
}
public function resume():void
{
// concrete classes that override this function should call super.resume()
// resume all processes
this._isSuspended = false;
createChildren();
invalidate();
}
public function get isSuspended():Boolean
{
return _isSuspended;
}
/**
* Moves the component to the specified position.
* @param xpos the x position to move the component
* @param ypos the y position to move the component
*/
public function move(xpos:Number, ypos:Number):void
{
x = Math.round(xpos);
y = Math.round(ypos);
}
/**
* Sets the size of the component.
* @param w The width of the component.
* @param h The height of the component.
*/
public function setSize(w:Number, h:Number):void
{
_width = w;
_height = h;
invalidate();
dispatchEvent(new Event(Event.RESIZE));
}
///////////////////////////////////
// getter/setters
///////////////////////////////////
/**
* Sets/gets the width of the component.
*/
override public function set width(w:Number):void
{
_width = w;
invalidate();
dispatchEvent(new Event(Event.RESIZE));
}
override public function get width():Number
{
return _width;
}
/**
* Sets/gets the height of the component.
*/
override public function set height(h:Number):void
{
_height = h;
invalidate();
dispatchEvent(new Event(Event.RESIZE));
}
override public function get height():Number
{
return _height;
}
/**
* Overrides the setter for x to always place the component on a whole pixel.
*/
override public function set x(value:Number):void
{
super.x = Math.round(value);
}
/**
* Overrides the setter for y to always place the component on a whole pixel.
*/
override public function set y(value:Number):void
{
super.y = Math.round(value);
}
///////////////////////////////////
// EVENTS
///////////////////////////////////
private function onInvalidate(e:Event):void
{
removeEventListener(Event.ENTER_FRAME, onInvalidate);
draw();
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
resume();
}
private function onRemovedFromStage(e:Event):void
{
suspend();
}
}
}
package com.view.ui.components
{
import com.core.Component;
/**
* MyComponent.as
*/
public class MyComponent extends Component
{
private var _source:String;
public function MyComponent()
{
super();
}
override protected function createChildren():void
{
//declare and add all elements of the component here
}
override protected function draw():void
{
super.draw();
//set the positions of the elements added
//this gets called on resizing the component
}
public function set source( value:String ):void
{
_source = value;
invalidate(); // call this function if you want to redraw the component based on the source.
}
}
}
+