« November 2007 | Main | January 2008 »
December 31, 2007
Scrolling Text Component
Here's another example of a Flex component. This one scrolls a message within a fixed area. The message can be scrolled vertically or horizontally. You can give it a try right here:
This component shows how to use custom properties, meta data to work with Flex Builder, and overriding functions.
Click here to download the source code. The download is a Flex Builder 3 Beta 3 project - if you do not have Flex Builder 3 Beta 3 from Adobe Labs, you can open the file as a regular archive and use the source code.
Posted by pent at 08:27 AM | Comments (18)
December 24, 2007
Component Pack from ILOG
I've been asked a number of times if there are more chart types, as well as other controls, available for Flex. Perhaps I'm late to the party, but I just came across this announcement (from October 2007) that Adobe and ILOG are teaming up to enhance Flex 3.
Here's a quick list of what's available in the ILOG ELIXR package. You can find out more on Adobe Labs: http://labs.adobe.com/wiki/index.php/Flex_3:ILOG
- Radar charts (also named spider charts)
- Full 3D charts including bar/column, area, line and pie
- Treemap component, for analyzing large data sets
- Scheduling component, allowing users to view and manipulate time series data
- Organizational charts
- Country maps for creating interactive reports or dashboards
Posted by pent at 11:07 AM | Comments (1)
December 20, 2007
Component Class - Part Five
The last article in this series showed how to write the CycleSelectButton from scratch. In this article I'll look at styling and skinning the component.
Skins versus Styles
One frequently asked question is "what's the difference between styles and skins?" This is a good question and it is confusing a bit because you specify a component's skins using specific styles on the component. For example, the upSkin style on the Button component.
Styles control the appearance of a component while skins are the appearence. Or put another way, skins use styles to present the component. Take the borderColor style. It's purpose is to specify the color of a component's edge. The component's skin can use that style to draw its border - which may be round or square, thick or thin (using the borderThickness style). The skin contains the look of the component.
The reason skins are specified as style is so you can build an entire look or theme using just style sheets (.CSS files). If skins were specified in ActionScript you would have to deliver a new SWF for each theme. Having the skins and other styles in CSS means you can change the theme of an application with a new style sheet.
There are two types of skins: graphical and programmatic. Graphical skins are bitmaps: GIFs, JPGs, PNGs, etc. In Flex 3 you can import graphical skins from Adobe Illustrator and Adobe Photoshop. You can use Adobe Flash CS3 to create animated skins (picture a button that pulses with color).
Programmatic skins are written in ActionScript. They are class files that usually extend mx.skins.ProgrammaticSkin which is a very lightweight class. The class uses its override of updateDisplayList() to render the skin using the drawing API (see flash.display.Graphics).
Each component has its own set of skins. For a Button there are 8 possible skins: upSkin (its normal state), overSkin (when the mouse hovers over it), downSkin (when the mouse is pressed over it), disabledSkin (when the Button's enabled property is false), selectedUpSkin (when the Button's toggle property is true), selectedOverSkin (toggle is true and mouse is hovering over the Button), selectedDownSkin (toggle is true and mouse is pressed over it), and selectedDisabledSkin (toggle is true and enabled is false). If you want to use graphical skins for a Button, you should supply 8 different image files. If your Button will never be a toggle, then you can supply just 4 skins.
Download Example
This is a zip file and contains a full Flex Builder 3 project. You will either need Flex Builder 3 from Adobe Labs or you can use Flex Builder 2 and import the sources into a project. This project contains the source from the previous articles as well.
If you decide to use a programmatic skin you can either make separate skin classes, or use a single class, or a combination. A programmatic skin can detect which skin style it is being used for and code within the programmatic skin class can adjust for it. If, for example, the skin class is being used for a Button's upSkin, overSkin, downSkin, and disabledSkin, the class can decide to draw a green-filled circle for the upSkin, a blue-filled circle for the overSkin, a blue-filled circle for the downSkin, and a gray-filled circle for the disabledSkin.
You decide what works best for the look you want. You can wind up with a collection of skins - both graphical and programmatic - that make your application look unique (or follow your company's user interface guidelines).
Applying Skins
Applying the skins is simple. I prefer to do it in a style-sheet to make them easier to change:
Button {
upSkin: Embed('assets/BlueButtonUp.gif');
overSkin: Embed(source='assets/CompanyIcons.swf',symbol='GreenButton');
downSkin: ClassReference('com.mycompany.skins.StandardButtonSkin');
disabledSkin: ClassReference('com.mycompany.skins.StandardButtonSkin');
}
This pretty wild Button has a mixture of skins: one is a GIF, another is a symbol out of a SWF, and two come from the same ActionScript class.
Specifying a graphical skin uses the Embed directive. For a simple image file the Embed names the file using a path that is relative to the application's main file, or an absolute path within the project. The example above uses a relative path. When a Flash SWF is used, the skin can be the entire SWF file or a specific symbol within the SWF. If you chose to use a specific symbol, the Embed directive names the file and the symbol within it.
Specifying a programmatic skin uses the ClassReference directive. The full class name, including its package, is given for the reference. The compiler will find that class and pull it into the SWF.
The main advantage of programmatic skins over graphical skins is scaling. Because programmatic skins use the Flash Drawing API, the skins scale and rotate very well. Graphical skins can easily become distorted unless you scale9grid specifications in the Embed directive. The scale9grid specifications let you specify a grid overlay on the graphic that tells the Flash Player which parts of the graphic to scale. Think of a rectangle where you want the 4 corners to never scale, the top and bottom to scale only when the graphic is stretched horizontally, the left and right edges to scale when the graphic is stretched vertically, and the center to always scale.
Going back to the CycleSelectButton component, here is how the createChildren() function looks currently:
override protected function createChildren() : void
{
arrows = new Arrows();
arrows.width = 20;
arrows.height= 20;
addChild(arrows);
linkButton = new LinkButton();
addChild(linkButton);
// add a listener for the click on the LinkButton.
linkButton.addEventListener(MouseEvent.CLICK, handleClick);
super.createChildren();
}
To redo this component using skins, you have to think about which parts of the component should be skinable. It seems like a good idea for the circle of arrows to be a skin. Maybe you want to make your own arrows using Photoshop, for instance.
Here is the modified createChildren() function that introduces skins:
var skin:Class;
skin = getStyle("arrowSkin");
if( skin == null ) skin = CycleSelectArrowSkin;
_arrowSkin = new skin();
_arrowSkin.name = "arrowSkin";
if( _arrowSkin is ProgrammaticSkin ) (_arrowSkin as ProgrammaticSkin).styleName = this;
_arrowSkin.width = 20;
_arrowSkin.height= 20;
addChild(_arrowSkin as DisplayObject);
This is a bit different. First, the value for the arrowSkin style is retrieved. The arrowSkin style is specified by metadata above the class declaration:
[Style(name="arrowSkin",type="Class",inherit="yes")]
Notice that the type of the style data is "Class" - you want to load the class definition for the skin, not just the name of the class. This works for Embed as well since a class is created from the embedded image data.
If no arrowSkin style has been specified, then the default class, CycleSelectArrowSkin, is given. Then the arrowSkin member variable is set with a new instance of whatever skin class was selected. This is the standard way to specify skins using styles.
Once the class instance has been created and arrowSkin is now set, you'll see it is given a name ("arrowSkin") and its style is set to this. What it means is that the skin will get all of the styles set on the component. For example, the CycleSelectArrowSkin uses a style called "arrowColor" to draw the arrow graphic. There isn't any way from outside of the CycleSelectButton code to associate this style with the arrow skin; the style is set on the component, along with the arrowSkin style shown above:
[Style(name="arrowColor",type="Number",format="Color",inherit="yes")] [Style(name="arrowSkin",type="Class",inherit="yes")]
With the skin inheriting the component's style, arrowColor among them, the skin code can draw the arrows.
Details
In this section I go through the steps in more detail . I'll use the sample CycleSelectButton available from the download with this article, but I will only show the skin for the arrows; the skins for the rest of the component work the same way and it will be less confusing to focus on one skin.
Step 1: Figure out what you want the skin to be used for. In this case, it is for the cycle of arrows and by making it a skin, gives a developer the chance to change the look of the component without re-writing the component.
Step 2: In the component class file (CycleSelectButton.as), define the style for the skin above the class definition:
[Style(name="arrowSkin",type="Class",inherit="yes")]
public class CycleSelectButton extends UIComponent
{
Make sure the type of the style is "Class". The name will be used in the style sheet or on the MXML tag for the component:
StyleSheet.css:
CycleSelectButton {
arrowSkin: ClassReference('com.adobe.examples.skins.CycleSelectArrowSkin');
or
arrowSkin: Embed('assets/ArrowSkin.png');
}
MXML:
<buttons:CycleSelectButton arrowSkin="com.adobe.examples.skins.CycleSelectArrowSkin"... />
or
<buttons:CycleSelectButton arrowSkin="@Embed('assets/ArrowSkin.png')" ... />
Step 3: Declare a member variable to hold the skin instance:
private var _arrowSkin:IFlexDisplayObject;
Notice that the type of the variable is IFlexDisplayObject - not CycleSelectArrow skin, not UIComponent, and not even ProgrammaticSkin. If you want your skin to be either a programmatic skin or a graphic skin, you need to use a data type that is common to both. IFlexDisplayObject fills that need. It is generic enough, but also allows you to position and size the skin.
Step 4: Create the skin. You can do this either in createChildren() or in commitProperties().
var skin:Class;
skin = getStyle("arrowSkin");
if( skin == null ) skin = CycleSelectArrowSkin;
_arrowSkin = new skin();
_arrowSkin.name = "arrowSkin";
if( _arrowSkin is ProgrammaticSkin ) (_arrowSkin as ProgrammaticSkin).styleName = this;
_arrowSkin.width = 20;
_arrowSkin.height= 20;
addChild(_arrowSkin as DisplayObject);
The getStyle() function is used to get an alternative skin class (ProgrammaticSkin or graphic) from the styles for the component. This is how a custom skin can be used from a style sheet or MXML tag (from Step 2 above). If no skin was specified getStyle() returns null. In this case a default skin is used. It is important that when using skins you are consistent and create a default skin; creating a skin as a default is always a good idea and perhaps it too can be extended and customized.
Once the skin class is chosen, the arrowSkin member (from Step 3) is set with an instance of this class. Now it is either a graphic skin or a ProgrammaticSkin. If the latter you must set the styleName of the skin to be this (or some other object instance which holds the styles). If you don't do this, the ProgrammaticSkin will fail when it uses getStyle().
You can size the skin at this step IF you know the size. If your skin is going to occupy the entire component's space, you can set it within updateDisplayList() (see Step 5).
Finally you add the skin as a child of the component. Note that you have to cast the skin as a DisplayObject since addChild does not accept IFlexDisplayObject parameters.
Step 5: Position (and optionally, size) the skin in updateDisplayList():
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList( unscaledWidth, unscaledHeight );
// position the arrowSkin
_arrowSkin.move( 10,10 );
Here the arrowSkin is moved into position. If you were to have a skin that required it to be sized, then you can do that too using skin.setActualSize( width, height ) where the width and height might be unscaledWidth, unscaledHeight or some derivative of those values.
That's all you need to do to use a skin in your component. Notice that none of the component's look has been done by the actual component code - it is all done by the skin. This gives your component a tremendous amount of flexability in how it is presented, not in how it behaves.
The Skin Itself
The CycleSelectArrowSkin is one of the files available in the download with this article. Here are some of the highlights:
public class CycleSelectArrowSkin extends ProgrammaticSkin
The class extends mx.skins.ProgrammaticSkin which extends flash.display.Shape. That's because skins should be very light-weight and be limited to just presenting graphics. However, one of the most powerful properties of Flex and the Flash Player is its flexability. You do not have to make your skins extend ProgrammaticSkin. You can use any class which implements the IFlexDisplayObject interface.
Since skins are so lightweight there isn't much else they do except override updateDisplayList():
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList( unscaledWidth, unscaledHeight );
var color:Number;
switch( name )
{
case "arrowSkin":
color = getStyle("arrowColor");
if( isNaN(color) ) color = getStyle("themeColor");
break;
case "arrowDisabledSkin":
color = 0xAAAAAA;
break;
}
drawArrows( graphics, color );
}
In this function, the skin's name is used to determine its color. If the skin is the "arrowSkin" then the color is extracted from the "arrowColor" style. If that was not defined, then the skin's color defaults to the "themeColor".
Using the themeColor as a default - whether it is the actual color or a darker or lighter version (see mx.utils.ColorUtil class) - is a good idea since that color flows nicely with the style sheet and theme idea.
Once the color is chosen the skin is drawn. The drawArrows function is the same as it was before:
private function drawArrows( g:Graphics, color:uint ) : void
{
g.clear();
g.lineStyle(0, color, 1);
g.moveTo(-10,0);
g.curveTo(-10,-10,0,-10);
g.curveTo(2.5,-11,8,-8);
g.moveTo(8,-8);
g.lineTo(6.5,-13);
g.moveTo(8,-8);
g.lineTo(2.5,-6);
g.moveTo(10,0);
g.curveTo(10,10,0,10);
g.curveTo(-2.5,11,-8,8);
g.moveTo(-8,8);
g.lineTo(-6.5,13);
g.moveTo(-8,8);
g.lineTo(-2.5,6);
}
Summary
That's all there is to skinning components:
- Figure out what you want to skin,
- extract the drawing into a class based on ProgrammaticSkin,
- add the skin as a style to your component,
- create an instance of the skin, and position it.
You should now be able to make reusable components for all of your Flex projects.
Posted by pent at 02:35 AM | Comments (5)
December 18, 2007
Atmospheres Music Player Update for AIR Beta 3
I have (finally) ported the Atmospheres AIR Music Player to Flex 3 Beta 3. You can get the complete code as a Flex Builder 3 Beta 3 project at the following link:
You will need the Flex 3 Beta 3 software from Adobe Labs. This will also install the newest version of AIR. You may find however, that older AIR applications will no longer run.

There are a couple of changes from the previous version of this application:
The music player uses a component I wrote called ScrollingText. This displays a moving banner at the top of the application showing the artist, track, and composer of the current song.
Drag and drop has changed. You can still drag both Albums and Tracks into the Playlist area, but the feedback is different. That's because in Beta 3, AIR applications use the native drag and drop. This means your AIR applications can exchange data with desktop applications. Very nice, but I liked the image proxies. Hopefully that will become an option by the final release.
Friday, March 7 2008: I've updated the link associated with this article.
Posted by pent at 09:06 AM | Comments (3)
December 13, 2007
Flex 3 Beta 3 Available
The third and final public beta releases of Flex 3 and Adobe AIR are now available for download on Adobe labs. These releases are focused on quality and performance, resolving numerous bugs from beta 2. This is your final chance to provide feedback on the release before launch, so please take this opportunity to take a final, thorough look. You can download the final beta releases of Flex 3, Flex Builder 3, and Adobe AIR on Adobe Labs at: http://labs.adobe.com/. Please also be sure to check out BlazeDS, the newest open source Remoting and Messaging project from Adobe.
Posted by pent at 08:20 AM
December 06, 2007
New Versions of Flash Media Server and Flash Player
Adobe in the News
On Monday, December 3, 2007, Adobe announced new versions of the Flash Media Server and the Flash Player. Here are some highlights:
- Flash Media Server 3: includes two offerings; Adobe Flash Media Streaming Server 3 for live and video on-demand streaming and Adobe Flash Media Interactive Server 3 for customized scalable video streaming services plus multi-way social media applications
- Adobe Flash Player 9 Update 3, previously code named Moviestar now includes H.264 standard video support the same standard deployed in Blu-Ray and HD-DVD high definition video players and High Efficiency AAC (HE-AAC) audio support
Adobe Flash Player 9, combined with Adobe Flash Media Server 3 enables the delivery of HDTV quality video to the broadest online audience and paves the way for high definition Adobe Flash experiences on consumer devices.
If you read carefully you'll see we are offering two versions of Flash Media Server. Why? Well FMS was often compared to Windows Media Server and some people complained that the price point for FMS was too high. What they failed to realize is that FMS was more than just a video streaming server. Unlike WMS, you can program FMS using ActionScript and do a number of behind-the-scenes tasks (such as authorization) that are not possible with WMS.
Adobe has a nicely priced version of FMS that does nothing but streaming. Iif you've ever thought about creating your own video blog or your own movie studio, you now how have a way to deliver high-quality video to virtually every desktop in a fast, and reliable manner.
Future of Entertainment
Normally I just post these announcements, but I feel compelled to add more in this case. You see, I am a television/video junkie. There's not much I won't watch. Have you ever watched one your favorite programs streamed over the web? Chances are you were watching the show in the Flash Player with the video streamed with Flash Media Server. Some sites still use WMS and you can tell which ones they are. Now with Flash Player 9 Update 3, FMS can deliver HDTV quality video right to your desktop.
Having the major networks make popular shows available for streaming is a huge step toward what I believe to be, the future of in-home entertainment. Today you can use your television as a computer monitor and to watch a home improvement show you go to HGTV.com or if you want to watch a recent episode of The Office you just go to NBC.com. It is just a little clunky to get directly to the shows you want to watch.
What I don't get is why advertisers aren't driving this more aggressively. As you probably know, the use of TiVO (I have 3 myself) has started to raise some alarms with advertisers. People just skip over the commercials. Who wouldn't? You want to watch the program, not someone patting themselves on the back for making a vacuum cleaner.
If you have watched a streamed video from the major networks you have noticed that it, too, has commercials. But you cannot skip over them. You are held captive and must either leave the room, close the laptop, or do whatever it is you did before you got a TiVO, to avoid them. This is what I mean - the advertisers are worried about viewership going downhill with the rise of TiVO use, yet right before their eyes is the emerging technology of video streaming over the internet. And they have total control. You can fast-forward and rewind and pause the program's video stream ala TiVO, but come commercial time you are stuck. Some sites post a "Video will resume in # seconds" countdown clock (which I tend to watch more than the commercial) followed by 'Click here to continue' button (I wish the video would just start back up).
The really cool thing for advertisers about watching television programs streamed over the internet is that they have many choices in their advertisements. There is the standard commercial inserted into the video stream. There is also all the space around the video player for ads. But what's most important, is the ability to have targeted advertising. Imagine that your location is readily available to the web page hosting the video. The advertising software can display ads for services and products local to you.
We are just at the beginning of this revolution in entertainment. Once the advertisers get a whiff of this, the money will start flowing to the web sites and the focus will be redirected. I hope this leads to a lot of improvements, but these things often get off to a rocky start. I just hope we all have the sense and patience to make this a rich and responsible way to get our entertainment in the 21st century. If I were TiVO, I'd start planning to be a leader and not let my market dry up.
Posted by pent at 09:42 AM | Comments (4)