Adding a MovieClip/Sprite from an external SWF to a skin


I’m trying to learn a little bit of Flex 4 development. I’ve done a lot of Flash/AS3 since more than a year now but I haven’t really gotten into Flex yet. From what I learned in a day, they did a lot of improvements in separating the logic from the presentation (design). Most of this is done through skins (i.e. separate mxml files defining how a control will look). Skins act just like a container; it can contain shapes and additional controls. If applied to a control, that control will inherit all the shapes and controls from that skin.

My first annoying stumbling block was trying to add an exported symbol (e.g. MovieClip, Sprite) from an external swf to a skin. The skin will be applied to a button and should apply a background using the exported symbol. There are two ways that I’ve come up with: using BitmapImage or SpriteVisualElement.

For BitmapImage, just add this to the skin (<s:SparkSkin> tag):

<s:BitmapImage source="@Embed('assets/assets.swf#CaptureButton')" />

The above will add a bitmap version of the exported symbol named “CaptureButton” from the SWF file named “assets/assets.swf” located in the project directory. The problem with bitmaps is they look horrible when scaled up so I wanted to add the CaptureButton as a Sprite or MovieClip (vector) instead. I did it using SpriteVisualElement which takes a few more lines to set up. You’ll have to add the SpriteVisualElement tag and add the external symbol to it through code (on the addedToStage event). Here’s the full code of the skin file using SpriteVisualElement:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
              xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
              xmlns:mx="library://ns.adobe.com/flex/mx"
              minWidth="21" minHeight="21" alpha.disabled="0.5">

  <fx:Metadata><![CDATA[ [HostComponent("spark.components.Button")] ]]></fx:Metadata>
  <fx:Script>
    <![CDATA[

      // embed our symbol (Sprite)
      [Embed('assets/assets.swf#CaptureButton')]
      private var CaptureButton:Class;

      /**
        * As defined in the SpriteVisualElement tag at the bottom of the page, this
        * event handler will be called when it gets added to the stage.
        */
      protected function mySprite_addedToStageHandler(event:Event):void
      {
        // create an instance of our embedded symbol
        var sprite:Sprite = new CaptureButton() as Sprite; // or use MovieClip if you're adding a symbol with more than 1 frame
        sprite.x = 10;
        sprite.scaleX *= 2;
        sprite.scaleY *= 2;
        mySprite.addChild(sprite); // add it to the SpriteVisualElement
      }
    ]]>
  </fx:Script>

  <s:states>
    <s:State name="over" />
    <s:State name="down" />
    <s:State name="disabled" />
    <s:State name="up"/>
  </s:states>  

  <!-- call mySprite_addedToStageHandler() when this element gets added to the stage -->
  <s:SpriteVisualElement id="mySprite" addedToStage="mySprite_addedToStageHandler(event)" />

</s:SparkSkin>

The SpriteVisualElement takes more lines to setup than BitmapImage. I hope that this is just a lack of knowledge on my part. There might be a way to add a Sprite/MovieClip with just 1 tag. For now, this works great and I’m fine with that.

Assigning the skin to a button should look like this:

<!-- assuming we named our skin "CaptureButtonSkin" -->
<s:Button id="captureButton" skinClass="CaptureButtonSkin" height="197" width="442" x="365"/>

Update 2010-08-26

After a night’s sleep I found it. Crap. It was this easy:

<mx:Image source="@Embed('assets/assets.swf#CaptureButton')" />

Face palm. Excuse me while I bang my head against the wall.