Not really an official Flexcerpt, but something that might be useful when embedding assets...
One thing that's been discussed a lot is the hassle of embedding assets in Flex and then adding them to the stage. At the core of the issue is that everything in the Flex world IS a UIComponent. This is necessary so that the framework can "talk" to components within it through a known API (particularly with respect to Containers). So if you try to create a custom class that extends, say flash.display.Sprite, and try to add it to the stage, you get a runtime error called something like "Type Coercion Failed". This is due to line 3301 in mx.core.Container (in the addingChild method):
// Throw an RTE if child is not an IUIComponent var uiChild:IUIComponent = IUIComponent(child);
As you can see, a check is made to see if the child being added implements IUIComponent, and if it fails that check, then the error occurs. The sole purpose of that line of code is to throw a runtime error (uiChild isn't actually used elsewhere in that method). Grant has a very simple and effective solution to this called DisplayObjectWrapper. Head on over there and grab it, but basically, the premise is that since ALL Container based components in the framework require children to implement IUIComponent (ie., extend UIComponent), you can first wrap the asset in a UIComponent before adding it to the stage. Note that NON-Container based components don't have that same requirement for its children, which is why this works.
In Grant's example, he uses a DisplayObjectWrapper mxml tag to draw the asset to the stage. Works great. Then I tought, ok, let's use ActionScript instead of mxml to add it to the stage. Problem is that for some reason which I couldn't figure out, I couldn't access my asset's class from AS (to be honest, I haven't really done this as I generally use mxml to add assets). Then I stumbled upon this...
It appears that when the asset is embedded into the swf, it gets assigned a classname that looks like "ProjectName_AssetClass". So for example, let's say you have a project called "PhilterBlog", and you embed the following asset:
[Embed(source="assets.swf#Logo")] public var Logo:Class;
Then you would do something like this:
import com.gskinner.ui.DisplayObjectWrapper; var wrapper:DisplayObjectWrapper = new DisplayObjectWrapper(PhilterBlog_Logo); addChild(wrapper);
Note the class name of the asset I used (PhilterBlog_Logo). Also note that you don't need to create an instance of your asset because DisplayObjectWrapper does it for you :)
Anyway, this is as much for my own reference as it is for others as I hadn't seen this elsewhere, but feel free to point me to other urls if this is widely known about embedding assets.
People viewing this should note that for your example to work the class specified below the embed tag, and the class used in the DisplayObjectWrapper need to match (i.e. both 'Logo' or both 'PhilterBlog_Logo').
you could also use:
[Embed(source="logo.gif")]
public var EmbeddedBitmap:Class;
private function onCreationComplete( event:FlexEvent ):void
{
// Create a new instance of the embedded bitmap and display it inside an Image instance
var bitmapAsset:BitmapAsset = BitmapAsset( new EmbeddedBitmap() );
var image:Image = new Image();
image.source = bitmapAsset;
imageContainer.addChild( image );
}
i have some examples of embeding etc from my FOTB pres here too if anyone wants further examples http://www.tink.ws/blog/flash-on-the-beach-was-blazin/.
Hey Tink,
Thanks for the alternate code. Strange, but when I try that code, I get an IDE error. Does it work properly for you?
Regarding your note:
"...the class specified below the embed tag, and the class used in the DisplayObjectWrapper need to match..."
Actually, this was my point exactly...the fact that you CAN access the asset using the name "ProjectName_AssetClass" (and that the names don't match). In fact, as mentioned above, if I take the asset class name specified below the embed tag and use it in AS, FlexBuilder gives me a script error in the IDE (seems to run ok though when compiled).
The other important part of this is that I couldn't reference that asset from another class if I wanted to reuse it in different places in my app (never tried it, but I imagine I could just add an embed to my class that needs to use it - is that the recommended way to do it?). However, when you use "ProjectName_AssetClass", all of a sudden you can use that asset from any class in that project (and I don't get IDE script errors). Maybe classes shouldn't be grabbing asset references like this, but it seems cleaner than having to embed the asset into every class that needs to use it.
Hopefully I'm not the only one experiencing this...
Hey Phil
Sorry i had copied and pasted that code out of one of my examples that contained another container 'imageContainer'. You need to remove the reference to that and make sure you have imported BitmapAsset, Image and FlexEvent for it to run.
"In fact, as mentioned above, if I take the asset class name specified below the embed tag and use it in AS, FlexBuilder gives me a script error in the IDE (seems to run ok though when compiled)."
Can you give an example of this? As you can see from running my example (when you've fixed it up with the above comments), you can access the class directly.
"The other important part of this is that I couldn't reference that asset from another class if I wanted to reuse it in different places in my app"
As long as the embeded asset is a public property of your class you should be able to access it. if its just a public prop, you would have to access it through and instance of your class, but if you declared it as static you should be able to access from the class directly. So you could in effect create a Library class and embed all your assets in there and assign them to publis static vars, then access them with Library.Asset.
Right I see what your saying with your example. Its an interesting method to get global access to embedded assets. If this method was used I would recommend embeddig all your assets in the same file, as you could get unexpected results when u embed different assets in different files but assign them to the same var.
It sounds a reasonable idea to embed everything in a class name Library or Assets and then use this method to have gobal access to them, but if your in a team and someone decides to embed someting elsewhere, with the same name it could cause a problem. At least if you embeded them as static in your class and referenced them through the class you wouldn't come across this problem. That said if you have a decent team and some set rules I can't see your method being a major headache.
Also on the same subject, i find this syntax
[Embed(source="assets.swf", symbol="Logo")]
a lot clearer than
[Embed(source="assets.swf#Logo")]
all intersting stuff! Thanks for the post!
Hey Tink,
Now that you mention it, setting up assets as static members is probably the way to go. Thanks.
Ok, I tried your example with the gif and BitmapAsset and it works fine. However, when i try to do the same with a symbol from a Flash 9 swf, i get a runtime error. Basically, i do the exact same thing with a swf symbol, but cast it to a MovieClipAsset instead of BitmapAsset. I get a "Type Coercion failed" error saying it can't convert the symbol to a MovieClipAsset.
Ok, i figured out the issue...
It appears as though the symbol from my swf was converted to a SpriteAsset instead of a MovieClipAsset. I did a quick test, and if your symbol has 1 frame, it's converted to SpriteAsset, but if it has more than 1 frame, it's converted to MovieClipAsset.
http://www.FIELD_MESSAGE_mondeld.com/
http://www.FIELD_MESSAGE_mondeld.com/
http://www.message_oloricel.com/