In an ActionScript 2 project I can create a new MovieClip, right-click on it on the library and select "Component Definition" to add parameters that can be referenced inside the MovieClip. This parameters can be easily changed in the MovieClips's properties.
Now, I'm working on an ActionScript 3 project but haven't been able to figure out a way to obtain the values passed in those parameters.
I defined a parameter named "textToDisplay" but when I write the following in the Actions for the first frame I get an error:
trace(textToDisplay);
This is the error:
1120: Access of undefined property textToDisplay.
Do you know how to capture the value of that parameter?
Thanks
PS: I'm using Adobe Flash CS3 Professional on Windows XP
In as3 you have to create an external class file with one or more public var
declarations that you will use (you can also use public get
/set
functions). Google this if you're not sure how.
In your external file, use the [Inspectable]
metadata tag just before your var
, like this:
package myPackage {
import flash.display.MovieClip;
public class MyComponent extends MovieClip {
[Inspectable]
public var myFancyComponentParameter:String;
[Inspectable]
public var myOtherFancyComponentParameter:int;
}
}
Then you can open the Component Definition dialog, set the Class field to the name of your external class (including package name), and Flash will automatically create parameters for your component based on your [Inspectable]
tags. Or you can create them manually.
Once you've set this up, you can access the component vars in timeline code:
trace("Here's my var: " + myFancyComponentParameter);
Details on the [Inspectable]
tag (including data types) are available at the metadata livedocs.
It's also a good idea to set the class name in the Linkage dialog too, if you want your external class to do anything other than hold component values.
I'd also recommend putting code in your external class, rather than in the timeline. It's more extensible that way. If you do this, just remember that your component parameters aren't set until after the INIT
event is fired. Here's how to listen for that:
// package and import statements omitted for brevity
public class MyComponent extends MovieClip {
[Inspectable]
public var myFancyComponentParameter:String;
public function MyComponent() {
// myFancyComponentParameter not set here yet
trace(myFancyComponentParameter); // prints null
addEventListener(Event.INIT, onInit);
}
public function onInit(e:Event) {
// now we can use component parameters!
trace(myFancyComponentParameter); // prints the param value
}
}
Considering how hard it is to find information about custom component setup I thought i would clear up some aspects of the process based on what I have experienced.
INIT EVENT:
For the most part aaaidan example above is correct with one exception.
addEventListener(Event.INIT, onInit);
should be:
loaderInfo.addEventListener(Event.INIT, onInit);
the loaderInfo property of a DisplayObject refrences a LoaderInfo from which your component gets its parameter settings from. the INIT event is called when it has gotten its data (alternativly you could use the COMPLETE event, which should fire directly after the INIT)
INSPECTABLE METADATA:
when your setting up properties to be accessed using the metadata [Inspectable] tag, you can also define default values using:
[Inspectable(defaultValue="whatevervalue")]
from what I have experience the parameters seem to have trouble dealing with anything other then a String (and perhaps Numbers), so I would suggest using set functions that take string values and use them to obtain the other values you may want. for example if you want to load a new instance of a specific named class
[Inspectable(defaultValue="flash.display.Sprite")]
public function set className(value:String):void{
var ClassReference:Class = getDefinitionByName(value) as Class;
_class = new ClassReference();
}
in this example if the parameter is set to "flash.display.Sprite" calling "new _class() will create a new Sprite instance.
SETSIZE FUNCTION:
if you want your custom component to resize in a way other then simply stretching the height and width values you need a public setSize function. this function will be called every time you resize your component in flash.
public function setSize(w:Number, h:Number):void{
_menuWidth = w;
_menuHeight = h;
}
now this works great when your resizing the component in flash but once you actually publish your swf file you will notice that it switches back to stretching width and height rather then using your setSize function (i dont know why but thats what it does). to fix this, in your onInit function you need to take the width and height, feed them into your setSize, and then reset the scaleX and scaleY values back to 1 :
public function onInit(e:Event):void{
setSize(width,height);
scaleX = 1;
scaleY = 1;
//add other functions that need to be run once the parameters are loaded
}
(if anyone finds a less messy way of doing this let know)
hope this helps someone get their custom components up and runing.
Finally got it working (using basic MovieClips without much extensions so far). I have two bits to add:
- The symbol needs to be exported for ActionScript (i.e. have a linkage definition). Setting the Class only in the Component Definition will not do. Without the export setting, the
[Inspectable]
tag is interpreted, but the rest of the code is completely ignored. Even things in the constructor of the class.
- The default value in the
[Inspectable]
tag doesn't seem to work when compiled, or rather it will result in null
. I was only using a String which IS in the Component Parameters box but traces out null
. Even after Event.INIT
(I'm tracing on click). It doesn't seem to be a case of "value not carried over", as inputting the default value manually will still result in null
. Setting a default in [Inspectable]
effectively defines a value that cannot be used.
P.S. using CS5.
I haven't used this specific functionality, but likely you will need to define a custom class for that MovieClip (just subclass MovieClip) and add that extra variable.
Actionscript 3 has moved away from the dynamic nature of actionscript 2, this can be a bit confusing to start with, but in the end it's much more robust.
I do not see an INIT event in the MovieClip class definition and it does not seem to be called.
I had the same problem - there is no INIT event for a MovieClip - but otherwise this solution works fine. The only way I could see to get around this is to use Event.ENTER_FRAME and remove the listener again the first time the handler is called. My component parameters were accessible from the next frame onwards, but I find it surprising that no official event exists when a movie clip is instantiated.
There is an ADDED_TO_STAGE event that would work better than the ENTER_FRAME event that steve-mann suggested.
In the CS4 10.0.2 release, you can right-click and add component parameters manually again.
Two Things to note:
- You WILL still need to wait for loaderInfo Event.INIT before you can reference the custom values (ie: loaderInfo.addEventListener(Event.INIT, initComponent)
- You will need to define the parameter on the 1st frame (var paramName) in order to be able to reference it without a compiler error.
Hope this helps you...I know it helped me!
~Greg