Advertisement
  1. Code
  2. Workflow
Code

Intro to Flash Camo: Part 1

by
Difficulty:IntermediateLength:LongLanguages:

Welcome to an introduction of the Flash Camouflage Framework. Flash Camo (for short) is a graphics framework that is broken down into 3 core areas: "Decals", the "CSS Parser", and the "CamoDisplay". These systems can be used individually or combined to fit your needs. When used together they form a powerful set of tools to help skin and style any Flash application. With Camo's modular approach, you can use as little or as much of the framework as you want.

In this two part tutorial we're going to build a simple website to show how easy it is to incorporate Flash Camo into your next project.

Preview

We're going to recreate the "Bobble Person Site Launcher" from http://jessefreeman.com.

1_bobblehead_preview

Step 1: Checkout Flash Camo 2.2

In this tutorial we're going to use Flex Builder. If you haven't worked in Flex Builder or need help getting a Flex Library project setup, take a look at my "Flash Development Sandbox Tutorial" (part 1 and part 2). This tutorial will also walk you through downloading and setting up Flash Camo from SVN. For this project we're going to be using version 2.2 of the framework, you can check it out here:

http://flash-camouflage.googlecode.com/svn/tags/FlashCamo_2.2.0_beta

2_flash_camo_svn

Step 2: Setting Up Our Project

Create a new project called BobbleHeadApp and make sure you link it to the Flash Camo SWC we checked out in step 1.

3_new_project

You will also need the following resource folders to get started. Download them from here and place them in your html-template folder. I've included an updated html-template file linked to swfObject along with the layout of our external resource folders.

4_bobble_project

Step 3: Creating a Flash Camo Doc Class

Now that we have our project and resources set up, let's start with our Doc Class (BobbleHeadApp.as). You should replace your doc class with the following code:

Sometimes when testing local files you may see the following error:


Error #2044: Unhandled SecurityErrorEvent:. text=Error #2140: Security sandbox violation: ... Local-with-filesystem and local-with-networking SWF files cannot load each other.

If this happens to you, add the following "-use-network=false" in your projects compiler Arguments. This will circumvent any Security Sandbox issues you may get while locally testing.

Now you should be ready to compile the swf and take a look at the output window. You will see "Hello World":

5_hello_world

If you check your browser's connections the font swf should have been loaded:

6_connections

Step 4: Creating a Global PropertySheet Manager

We're going to need a central place to store and access our css properties. Before we do this let's talk about the CamoPropertySheet. You may have used CSS with Flash in the past but this is something completely new and unique to Flash Camo. Camo's custom CSS parser, the "CamoPropertySheet" (found inside of the "camo.core.property" package), goes well beyond the native StyleSheet class by supporting style inheritance, pseudo selectors and merging styles on the fly. The goal of the CamoPropertySheet is to make styles something you can apply to any of your classes instead of just TextFields. CSS is a great way to define your class's properties in an external file and Camo helps convert these css styles into property/value pairs you can apply to any Object. Camo also has a CamoPropertySheetManager (found inside of the "camo.core.managers" package) class for handling multiple CamoPropertySheets in one application.

Since we will need all of our classes to have access to the CamoPropertySheetManager we're going to create a Singleton. This Singleton will enforce one instance of our CamoPropertySheetManager. I'm not a big fan of Singletons, but in situations like this they're a necessary evil. We'll need a single class instance in charge of managing and returning requested PropertySelectors. I will explain later what a ProperySelector is and how it will function in our application.

Let's create a new class called "GlobalPropertySheetManager" and put it in the "com.jessefreeman.managers" package.

7_create_global_pms

Here is the class's code:

There are many ways to create a Singleton and the discussion is a little out of scope of this tutorial. Let's quickly talk about what is happening here. Since ActionScript 3 classes are unable to have private constructors there is no way to hide the constructor of a class. Instead of allowing the class to be created through the usual "new" construction we will enforce calling the GlobalPropertySheetManager.instance to get a reference to the class. The instance getter checks to see if the class has already been created, if the class doesn't exist it creates a new CamoPropertySheetManager. If the instance exists it will return a reference to that instance. This ensures that we only have 1 instance of the CamoPropertySheetManager in our entire application. Now we're ready to start loading in our CSS.

Step 5: Loading PropertySheet CSS

The CamoPropertySheetManager has no way to load CSS, instead we'll supply the load mechanism and tell it to parse the loaded data. We'll start by creating our load method by making use of the URLLoader. Add the following methods to our Doc Class after the "onFontsLoaded" function:

You will also need to add the following properties to the Doc Class:

Then import the following classes:

Finally, we'll just alter our onFontsLoaded method to call loadPropertySheet by replacing:

with:

Since the URLLoader can load in any text file, we simply load in our own custom CSS then pass it off to the CamoPropertySheetManager instance that we got from the GlobalPropertySheetManager. Notice how we called "parseCSS" and passed in a name for our PropertySheet along with the string data we just loaded. That's all you need to do in order to have Camo parse your css. Later we'll talk about how we get our styles out, but here is a little more info on the PropertySheet system in camo.

Once the CSS is parsed, you can retrieve an Array of selector names by calling the "selectedNames" getter. A selector represents the name of the particular CSS style and its collection of values. The "getSelector" method will return the selector and its properties as a "PropertySelector". New selectors can be added to the CamoPropertySheet by calling "newSelector" and passing a selector name and a PropertySelector instance. Finally, you can duplicate a CamoPropertySheet by calling the "clone". We'll cover this more as we start to build out our components.

Step 6: Testing The CSS Parser

Now is a good time to test that our CSS parser works. Let's open up the css file in "html-tempalte/css/main.properties.css" and add the following style:

If you're working in Flex Builder and modify files in your html-template folder you will need clean the project. You can do this by going to Project > Clean... and selecting the projects you want to clean. When you clean a project, it makes a fresh copy of the html-template folder over to the bin folder. Let's say you modify something in html-template then add a new line of code. Flex Builder automatically preforms a clean. This situation only happens when you edit a file in html-template and do not do a clean. Trust me, this step will save you countless hours of frustration trying to figure out why your changes are not showing up in the browser. I usually map the clean project action to option + command + c since I use it so much.

8_clean_menu

Now if you recompile the swf and look at the output you should see the name ".TestStyle" selector name next to the "PropertySheetSelectors" trace.

9_teststyle_trace

Let's try to retrieve our style and trace it out. Replace:

inside of onCSSLoad from our Doc Class with this:

Now when you compile you should see the following:

This is the string value of our PropertySelector. Looks like an object right? Well that's because it is! Camo's css parser converts css selectors into native objects. It is important to note that each value is still a string. Later we will talk about how to convert these strings into natively typed values so you can apply them to any object or class in your application. Let's start building the foundation for our project.

Step 7: Creating an AbstractComponent

Now we're ready to start building our components. We want all of our components to inherit the ability to automatically find their own CSS style. If you're not familiar with what an Abstract Class is, you may be surprised to hear that you might already be using them.

A simple explanation of an Abstract class is any class you create that has some core functions but has to be extended to added specific functionality.

Abstract Classes, much like our Singleton, should not be directly instantiated. Think of Abstract class as Interfaces but with code in them. We're simply setting up a few functions all components will need and each component will add the additional logic they require. We're going to call our Abstract Class "AbstractComponent" and put it in the "com.jessefreeman.components" package.

10_create_abstract_comp

Let's take a look at the code:

Even though this is a small class there's a lot going on. Let's start with the fact that it's extending the CamoDisplay. Normally we would extend Sprite or MovieClip for our display classes but because we want to take advantage of Flash Camo's BoxModel we need to build off of the CamoDisplay. We'll talk about the BoxModel and CamoDisplay a little later.

If you check out the constructor you will notice we're requesting two items, self and id. As we go through the constructor we do a verification that the class can only be instantiated by passing a reference of itself back into the constructor. You will see how this works with our "concrete" components (a concrete class is any fully functional class that extends an Abstract class). The other property id is important because we will be using that to look up the component's id from css. Once the Abstract validation has passed, we call the parseStyleName method.

The parseStyleNames method is doing something special for us. If you have worked in html and css you may know that you can overload a ID or Class tag by supplying multiple CSS selector names separated by a space. In this method we allow you to add multiple IDs separated by a space and we parse them out into individual ids. The last ID becomes the main ID for the class and we add a "#" to it automatically. We also add the class's name, from a getter of the CamoDisplay called "className", to our list of selector names. Let's look at the init function next to see how we use this.

In the init function we're doing two things; getting our selectors from the GlobalPropertySheetManager and then applying the css properties to the component itself through the applyProperties method. Take a look at how we're calling the getSelector method on the GlobalPropertySheetManager. This part may make your head explode but don't worry, I guarantee that at the end of the next few steps your code will compile and run fine whether or not you fully understand what's going on.

First off, we want to get an instance of the CamoPropertySheetManager so we call the GlobalPropertySheetManager's instance property. Remember this is a Singleton and we only have one instance of the CamoPropertySheetManager. Next we're calling its function "getSelector" but instead of passing in the names of each selector we're calling a function of the "getSelector" function. I know this is crazy but it is something built into the language. See "getSelector" is a rest function in Flash. This is a function that does not have a set number of parameters so you can pass in as many items as you want. Here is what the function actually looks like in the source code:

See the "... selectorNames"? That tells the function you will get any amount of selector names, so be prepared. Since we can't just pass an array into the "getSelector" method (because it would simply see it as 1 array variable) we have to call a special function called "apply" to pass in an array of arguments. The moral of the story is that you can pass in as many selector names as you want into the "getSelector" function and the CSS parser will merge them all into a single PropertySelector. If you want to understand more about rest statements in Flash check this out.

Now that's out of the way, let's look at an example to illustrate what this class will do.

Step 8: Testing The AbstractComponent

We're going to perform a quick test to show how the AbstractComponent and BoxModel inside of the CamoDisplay work. Create a class called "SimpleDisplay" in the "com.jessefreeman.components" package.

11_create_simple_display

Here is the class's code:

This is a very simple class, it just extends the AbstractComponent and passes a reference of itself up to super (in order to pass the AbstractComponent validation) and also passes up its id. Let's test it out by going back to our Doc Class and adding the following after our Hello World trace inside of the "init" function:

and import:

Now if you compile the swf, you won't see anything, but the SimpleDisplay instance is there. Go into your CSS file and change the name of the ".TestStyle" to ".SimpleDisplay". Now recompile and you should see your SimpleDisplay.

12_boxmodel_test

Amazing, right? The SimpleDisplay automatically found its CSS Class name and applied its values. Any instance of the SimpleDisplay will automatically apply the ".SimpleDisplay" CSS Style to itself now. Let's add the following style to our CSS sheet:

Now when you compile you'll see that the ID of the Component is overriding the base class style.

13_boxmodel_test_2

This is a very powerful way to customize the look and feel of your application. Now you can use CSS to style any class that extends the AbstractComponent. This is all made possible by Camo's BoxModelDisplay. The "BoxModelDisplay" allows us to apply Margin, Padding, Border and a Background (Color/Image). Camo's BoxModel works exactly like CSS's. Here is a diagram:

14_box_model

As you may recall, our AbstractComponent extended the CamoDisplay which in turn extends the BoxModel. Well, the CamoDisplay not only inherits all of the BoxModel's layout but it also adds a few extra features. You can read about all of the BoxModel and CamoDisplay's properties in the docs folder of your Flash Camo checkout.

Step 9: LabelComponent

We're going to create a simple component that will handle all of the text labels we need in our application. This is also a good component to help illustrate how the ProperySelector works. To get started, create a new class called "Label" in "com.jessefreeman.components" package.

15_create_label

Here is the code:

As you can see, this label component functions like a TextField through composition. I do this by creating a instance of a TextField and uses setters to update its values. This may seem like over-kill, but by doing things this way I take advantage of two features from Flash Camo. First off I extend the AbstractDisplay > CamoDisplay > BoxModelDisplay set of classes so I get CSS styling and BoxModel for "free". Also, I no longer need to create a separate TextFormat to style the TextField and apply it each time there's a change. This component allows me to simply apply TextFormat properties and it automatically updates the TextField instances properties. This is important when we look at how PropertySelectors are applied.

I have already shown you how our AbstractComponent automatically applies css styles to our components but let's look at what goes on behind the scenes in the CamoDisplay when we call "applyProperties". Here's what the code looks like:

A few things are going on here. First, all properties are cleared from the CamoDisplay. Next, we use a utility class called PropertyApplierUtil to apply a PropertySelector to the CamoDisplay instance. I mentioned earlier that PropertySelectors are Objects created from CSS selectors. Well the values of the object are strings, but we will need a way to convert a font's size to a number. This utility automates the process by analyzing the value types of a class's public variables and getters, then converts the matching PropertySelector's values to the correct type. Here is an example.

Let's say you want to set the font size on our Label component. You may have a style that looks like this:

When you apply the ".Label" PropertySelector to the Label instance (remember this is done automatically for us) the PropertyApplierUtil looks for a property called "size" on the Label instance. Once it finds it, it checks the properties value. Since we have a getter called size that accepts a number value, the utility will automatically convert the PropertySelector's size value into a number and set it on our component. You don't have to do anything special, the utility natively handles Strings, Number, Arrays, Objects, Colors (units) and a few other types. As long as your public variable has a type the utility can convert, any matching properties will automatically be set. We will see this in action in the next step.

Step 10: Using the Label Component

Let's go into our Doc Class and replace our SimpleDisplay demo by replacing the init function with the following:

Then create a new function under our init function:

Don't forget to add the following parameter:

As well as our import:

Finally, we'll need to add the following styles to our css file:

Now if you compile the swf you should see your label with the text "ANATOMY OF JESSE FREEMAN".

16_label_preview

The label automatically used ".Label" along with "#siteLabel" and styled itself. See how easy that was? A few lines of code, some CSS and we're up and running in no time.

Now you have a reusable Label Component that can by styled with css. This class is by no means finished. You can continue to add as many getters or setters as you need to make this Label fully customizable. I simply provided you a base to get started with. As you begin to extend off the framework it's important to understand some of the underlying draw logic.

Step 11: CamoDisplay Invalidation

You may have noticed from our Label component that the "invalidate()" method is called after we change a value in any of the setters. Redrawing the BoxModel and display is very expensive so to help alleviate the burden of constantly refreshing the display, the CamoDisplay waits until the next frame to redraw itself. This technique is used in Adobe's own components and is very efficient in cutting down on waisted cpu processes. It is something you should keep in mind when extending the CamoDisplay and using invalidate on your own custom setters.

The other important method you should know about is "draw()". After the display has been invalidated and a new frame is being rendered by the Flash Player, draw gets called automatically by the CamoDisplay. If you have custom display logic this is the best place to put it. Once "draw" is called, the invalidate flag is reset and the CamoDisplay will not redraw itself until it is invalidated again.

If you are doing complex animations like changing the width and height or require constant updates, you can override the invalidation by calling "refresh()" at any time. This will immediately force the CamoDisplay to redraw. Use this when you need to have constant display updates since it can become very intensive to render.

Step 12: Create A Bobble Container

We're going to create a class called "BobbleContainer" in "com.jessefreeman.components" package

17_create_bobble_container

Here's the code:

In our Doc Class, let's create a BobbleContainer instance to test our code with. Let's add the following function below createLabel:

You will need the following property:

then import:

In order to get this to work we will need to add a few more things. In our init function add the following:

Below the init function add:

We're almost done. Add the following to your CSS file and hit compile:

You should now be looking at a red box with a white border which bobbles when you move your mouse cursor over it.

18_bobble_test

Now that I've fully introduced Flash Camo's CSS parser I'm going to refer to it as Properties/Property Sheet instead of CSS from this point on. You're encouraged to think of Camo's PropertySheets as a natural extension of configuring the property values of your classes. Go ahead and change the values of the "nodding-range" or the "nodding-hit" to see how it works. Imagine configuring your entire application without having to recompile! Not only that but you can simply restyle an app by pointing it to a new PropertySheet.

Before we go, let's take a look at one last thing. Notice in our PropertySheet the ".SimpleDisplay #TestContainer" selector. Flash Camo supports selector inheritance. We refer to "#TestContainer" as the subject and ".SimpleDisplay" would be an ancestor element. If you were to call "getSelector" for " #TestContainer" the parser will automatically return a PropertySelector with properties from ".SimpleDisplay" and "#TestContainer" merged together. Any conflicting properties will be overridden by the subject style. Pretty cool right?

Step 13: Bobble Person

Now we're ready to create a class that will manage our BobbleContainer body parts. Let's create a Class called "BobblePerson" in the "com.jesseFreeman.components" package.

19_create_bobble_person

Here's the code:

As you can see here, we have a few methods revolving around setting up, creating and updating body parts. This class creates parts once the partIds setter is given a value. We're doing this through a setter because we will be using our PropertySheet to pass in the array of parts. Once we have a list of parts the createParts method is called. It loops through the partIds Array and creates new instances of the BobbleContainer. Each container is given an ID then pushed into an array called partInstances so we can keep track of all of the parts.

Our final function is for updating the parts. Remember the enter frame loop we set up in the Doc Class that updated the demo BobbleContainer? We'll connect that loop to the BobblePerson's calculateBobble method and it will manage calling calculateBobble on each of our parts. This way we only have one enter frame loop running in our app at any time.

Now we're ready to set this class up. Let's replace a few things in our Doc Class in order get our BobblePerson up and running. Start by replacing your "createPerson" method with the following:

Next do a find and replace for "bobbleTest" with "bobblePerson".

20_find_and_replace

Then replace:

with:

Make sure you also import:

Finally, you'll need to replace your entire PropertySheet file with the following:

If you do a quick compile you'll see a bunch of semi-transparent boxes overlapping each other, which bounce when you roll your mouse over them.

21_body_demo

We have the beginnings of our website. Next up we'll add Labels to each of the parts so we can keep track of them.

Step 14: Adding Labels to BobbleContainers

Let's go into our BobbleContainer class and add the following function after init:

Next modify the init function by adding the following:

above :

You'll also need to create the following property:

And import our Label class:

As you can see we're creating our new label and using the parent class's "id + “Label”" for the id. This allows us to give a unique id to each label created, yet still allows us to style each one via its Class Name. Let's add the following to our PropertySheet:

Now if you compile you'll see that all of our Labels are working and are getting configured by CSS!

22_body_demo_2

To Be Continued..

We've gone over a lot of stuff in this first tutorial. It's best that we take a break and let it all soak in. Next we'll go over how to skin our BobbleContainer using Decals, add some interactivity, optimize/clean up the code and talk about deployment. Stay tuned!

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.