Advertisement
  1. Code
  2. Workflow
Code

Intro to Flash Camo Part 2

by
Difficulty:IntermediateLength:LongLanguages:

Welcome to the part two of my introduction to the Flash Camouflage Framework. In part 1 we built the foundation for our site, components, labels, css parser, and set up our PropertySheet. In this part we're going to focus on the design side of our site by cleaning up the layout, skins and adding interaction.

Let's get started.

Preview

To refresh our memory, this is the final product we're going to create. It is the Bobble Person Site Launcher I use on http://jessefreeman.com.

1_bobblehead_preview

Step 15: Decals Sheets

I've talked about creating a Decal Sheet System before, but now we're going to take advantage of Flash Camo's own built in system. Let's talk about how Decals work in Camo.

The main feature of the framework is the DecalSheet system (located in the "camo.core.decal" package); made up of the DecalSheetManager, DecalSheet and Decal classes. The DecalSheet concept was inspired by the decals you would get with model airplanes. Each model kit would contain sheets of graphics and on each sheet you could peel off a decal and place it on the model. Camo's version of the DecalSheet allow you to load in external images, cut out decals and skin your application with them.

For this step you will need Photoshop CS 3/4 to open the psd. You can download it from here.

Once you have downloaded the PSD, open it up and take a look.

2_bobble_head_skin

As you can see we have our simple design. I've gone ahead and done all of the prep work for you so let's just go to "save as" and create a new PNG. Note: if you go to "Save For Web" you will see the slices we'll be using later in the tutorial.

We'll save this png as "default.png" to our "html-template/images/skins" folder in our BobbleHeadApp project. You can also right-click on the following image and use it instead of the PSD. Make sure you save it as "default.png"

3_bobble_head_skin

Now that we have our skin, we need to create a Global DecalSheet Manager.

Step 16: Create a Global DecalSheet Manager

Our site is going to make extensive use of the DecalSheet system, but first we're going to need to come up with a way to make it accessible throughout our application. Just like we did with the GlobalStyleSheetManager, we're going to create a Singleton for our DecalSheetManager class.

The DecalSheetManager (located in the "camo.core.managers" package) is the manager for the decal system. It handles the xml that defines a list of DecalSheet images and coordinates for cutting out each Decal. It also stores a collection of DecalSheets to make creating complex Decal lookup tables easier to manage. You can configure DecalSheets and Decals on the DecalSheetManager at run time or with XML. Once this data is set, the DecalSheetManager goes out and gets all the images it needs for the DecalSheet images.

Now we're ready to set up our GlobalDecalSheetManager class. You'll need to create a new class called "GlobalDecalSheetManager" and put it into "com.jessefreeman.managers" package.

4_create_global_decal_sheet

Here's the code for the class:

This should look familiar to you by now, so there isn't much to go over. Let's talk about how to load in DecalSheet XML and parse it.

Step 17: Defining Decals

We're going to modify the DecalSheet xml in our htm-template folder. In order to create our decals we'll need to know the x,y,width and height of each decal we want to use. Here is a quick mockup of our PSD with the coordinates.

5_decals_coords

Now that we have all the values we need, replace the contents of our decahsheet.xml in the html-template/xml folder with the following:

This xml should be easy to follow, we're defining our DecalSheet source then defining each decal and the sheet they belong to. Notice how the sheet has an attribute to preload, we're going to use DecalSheetManager's loader to prelaod all of our site's images. This will play a more important role when we preload several DecalSheets later on.

Step 18: Loading DecalSheets

The DecalSheetManager uses xml to create DecalSheets and Decals. We'll need to load in some XML first then we can pass it off to the GlobalDecalSheetManager's DecalSheetManager (try saying that 3 times fast).

Let's start by adding the following methods after our "onPropertySheetLoad" method in the Doc Class:

You will also need to import the following:

We just added a lot of code so let's take a second to go over what's going on. First we define the "loadDecalSheetData" method. All we're doing here is creating a new urlLoader and having it load our decalsheet.xml. When the load is completed we call "onDecalSheetDataLoad". This method handles removing the event listener from our URL loader and passes off the XML to the instance of the DecalSheetManager obtained from our GlobalDecalSheetManager Singleton. We also added two listeners; one for the notification of the "next" preload initiation and the second is when the preload is completed. When we're done loading we call "onDecalSheetLoad", remove our listeners and call init.

Now we have to remove the "init" call from our "onPropertySheetLoad" method. Replace that function with the following:

If you compile, everything should look the same but we're now loading in our DecalSheet xml along with the DecalSheet image.

6_decal_xml_and_sheet_image

Step 19: Decal Display

We'll need a component to display our Decal in. Normally you can take advantage of the BoxModel's background image property to automatically load in any image you would need, but since our body parts need to be centered we'll have to position them by hand.

Let's start by renaming our "SimpleDisplay" in "com.jessefreeman.components" to "DecalDisplay".

7_rename

Once you've done that, open the class up and replace its code with the following:

As you can see, we have a few properties that we can use to style this class from a PropertySheet. Let's take a look at the public variables, pixelSnapping and smoothing should look familiar if you have worked with the Bitmap Class before. These just help with making our Decals look smooth when they bobble around.

The main functionality of the class is the setter for src. As you can see it accepts a decal name, then requests the Decal from the GlobalDecalSHeetManager. If the decal exists we add it to the display. Let's talk about Decals a little.

A Decal is a Bitmap that contains a reference to the DecalSheet it was cut out from. Now that you have seen how we get xml data into the DecalSheetManager, let's talk about how to retrieve Decal instances. When you call "getDecal" on the DecalSheetManager or DecalSheet, you need to supply the name of a Decal. You can check if a Decal exists by looking through a DecalSheet's "decalName" Array. Once a Decal is requested, the Decal's name gets passed to the parent DecalSheet through the "sample" method and the Decal's BitmapData is returned inside of a new Decal Instance.

Since all Decals contain a reference to the DecalSheet it was cut out from, this connection allows the Decal to receive updates from its parent DecalSheet. You can change a DecalSheet's BitmapData at any time just as you would any other Bitmap instance. Decals listen for "Event.CHANGE" events from their parent Sheet and once an event is received, it resamples the DecalSheet and updates its own BitmapData. Later we'll reskin an entire application on the fly by changing the BitmapData of our DecalSheet.

Step 20: Using The Decal Display

Now that we have our DecalDisplay we need to add it to our BobbleContainer. In BobbleContainer, add the following method after "get active":

Also we'll need to create the following property:

So all we're doing is adding a setter for src that we can pass into a new instance of the DecalDisplay. Notice that we're using "addChildAt"? Since we add our label, we want to make sure that the DecalDisplay is at the lowest end of the display list. Now we have our DecalDisplay in place, we just need to set up some property styles.

Step 21: Styling Decal Displays

We have everything we need in place to start displaying our Decals. All we have to do is add some new properties to our PropertySheet. Take a look at this sample style for the DecalDisplay then we'll update the entire property sheet:

As you may have noticed earlier when we create our DecalDisplays in the BobbleContainer, we pass in the BobbleContainer's id and the string "DecalDisplay" so each instance has a unique id. In the above example we've added src to refer to the name of the Decal we want to use and then have a corresponding style with the x,y offset for the decal. Replace the contents of your "main.properties.css" with the following:

Now you have a clean PropertySheet with our decals correctly connected. If you do a compile you should see all of the body parts in their correct place along with our labels.

8_bobble_head_preview

Step 22: Focus Event

As we begin to add interactivity to our app we'll need a custom event to track mouse interaction on the body parts. Let's create a new class called "FocusEvent" in "com.jessefreeman.events"

9_create_focus_event

Here's the code:

So in this FocusEvent class we have added two new properties to the event's default constructor, "text" and "skinName". Text will be the label of the body part we roll over and skinName will be used later when we start to dynamically reskin our app. We also have two constants representing our states, "inFocus" and "lostFocus".

Let's dispatch this event by going into the BobbleContainer class and add the following line to the end of the "onRollOver" method:

Then add the following to the "onRollOut" method:

Also make sure you import the FocusEvent:

Now we have two events being dispatched letting us know the state of BobbleContainer. Before we're done we need to add a new public variable to the BobbleContainer:

We pass this variable into the in focus event that gets dispatched. You will need to modify your css with the new rollOverText. Replace these styles found in the /* BobbleContainers */ comment block with the following:

Step 23: Updating Body Label

Now we have all of the roll over text in place it's time to display them. You may have noticed that the "body" part doesn't have any rollOverText. We're going to display the body part's text here. Let's go into the BobblePerson and make a few modifications.

At the end of the "createParts" method add the following two event listeners:

Below the "createParts" method add the following:

We'll need to add a new getter so put the following under get "partIds".

We're almost there, now let's make sure you have the following property:

Then import the follow class:

Before we test this, we just need to update our ".BobblePerson" css style to include the following property:

Now do a compile and roll over the body parts.

10_roll_over_test

Notice how we can change the body part that will display the text at any time by modifying the part-display-id in our css. Let's add in the final set of logic to our site.

Step 24: Adding Click Logic

Now we're going to add some listeners to track when a BodyPart is clicked so we can open a corresponding url in a new window. Go into the BobbleContainer and replace "addEventListeners" and "removeEventListeenrs" with the following code:

We're simply adding a listener for Mouse Click. Add the following method below "onRollOut":

Let's add a new public variable for our urls:

Import the following classes:

All we need to do is modify our PropertySheet to include urls for each part by replacing the "/* BobbleContainers */" comment block with the following:

Notice how we have added url properties. This is how we tell Camo's CSS parser to convert urls into URL Requests. Now when a user clicks on a body part we simply pass off the url request set by the PropertyStyleSheet to the "navigateToURL" class.

If you would like the Bobble Parts to act as buttons, simply add the following to the ".BobbleContainer" style:

Now all of the BobbleContainer classes will automatically act as buttons. You may want to change one more style, the "#body", so it doesn't have mouse interactivity. Simply add the following to the property selector:

Now it overrides the Class's default settings and will not have mouse interactivity.

Let's look into how to do some advanced skinning.

Step 25: Advanced Skinning

When you opened up the PSD you may have noticed a few extra "skins" in the Body Skin folder.

I have prepared the following skins for us to use. You can download the zip here and put the skins in your html-template/images/skins folder.

Now you have each skin let's look at how we can load them all in.

Step 26: Loading Multiple DecalSheets

Loading in multiple DecalSheet images is as easy as modifying out xml. Let's replace our decalsheet.xml with the following:

All we've done here is added four new DecalSheets to preload. Compile the site and check your connections to make sure they are being loaded.

12_skins_being_loaded

Step 27: Adding Reskin Logic

Now that we're loading in our skins, let's add some logic to handle dynamically changing the skin bitmapdata. Let's go into our BobblePerson class and add the following two functions:

Let's talk about what's going on here. We're going to take advantage of a neat feature of Camo's DecalSheet system by replacing the bitmap data of our default skin with BitmapData from other skins. In order to do this we need to have a reference to the default DecalSheet as well as its BitmapData. We do this in "saveDefaultBitmapData". Next we need to add logic to switch skins. This happens in the "switchSkin" method. As you can see we set up a variable to hold our new BitmapData.

Next we test to see if the skin is "default" or something else. If it's the default skin we get the BitmapData from "defaultSkinBMD". If it's another skin we'll ask the GlobalDecalSheetManager's instance for that sheet. Lastly, we make sure we have a valid BitmapData in our newSkinBitmapData variable then set the BitmapData of our default skin to the newSkinBitmapData.

We need to add the following variables:

and make sure you've imported the BitmapData class:

Finally we'll call "saveDefaultBitmapData" in the setter for "partIds". Make sure your setter looks like this:

Now let's go into our BobbleContainer class and add the following property:

Next you will need to modify the dispatchEvent in the "onRollOver" method to look like this:

Notice how we're now passing up the skin value through the event? This will tell the body the correct skin to use when there's a roll over.

Let's go back to our BobblePerson and modify the "onContainerRollOver" and "onContainerRollOut" methods to look like this:

Now we just have to modify our PropertySheet to add a skin name to our body parts. Replace the /* BobbleContainers */ comment block with the following:

Now if you compile, you will see the skin of our bobble guy change depending on which body part you roll over.

13_reskin_preview

Notice how quickly everything is reskined. This is why Decals are so powerful. You can change the look and feel of your entire application on the fly by changing the BitmapData of your DecalSheets at runtime.

Step 28: Deploy

Now our site is done and we're ready to deploy it to a server. This is fairly easy to do in Flex builder and a step most people over look. Simply go to the Project menu and select Export Release Build.

14_bin_release

Once this runs you will have a new folder called bin-release along with your bin-debug. Everything looks the same, but if you check out the side of our BobbleHeadApp.swf you will notice that the release build is about 24k and the debug version is 36k. That is barely 66% of the original size. I know when you are only talking about a few k it's not a major deal, but every k counts. Also, in larger projects this can be a significant saving.

Now you are ready to copy this bin-release folder over to your FTP server and make it live.

Conclusion

As you can see, we have created a simple Flash Site using Flash Camouflage in less then 30 steps. By now you should have a better understanding about the power of incorporating Decals and CSS in your next project. You have also seen how easy it is to build components that work with Flash Camo's three main features. Like all frameworks there is a learning curve and this is only a small sample of what is possible. Also, Flash Camo is still in Beta so there may be small bugs or code cleanup as the project matures.

If you encounter any issues, please leave a comment or submit an issue to the issue list. Remember Flash Camo is completely open source, you should check out the code and see what is going on under the hood. A lot of advanced techniques are being used so it's a great place to learn how a framework is put together. If you use Camo in one of your projects let please me know..

Thanks for following along!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.