Styling Flex Custom Components

After having understood in details the Flex Component Life Cycle, let’s look at ways to add styles to Flex custom components.

You can find a lot of information about styling a component in Adobe documentation, but the most interesting parts are somewhat hidden at the bottom of different pages of multiple sections.

So, here’s my synthesis describing the two “best ways”1 of Styling a Flex Custom Component efficiently.

Introduction

Let’s start by listing our objectives. It must be possible to set style properties of our custom components:

On the development side, we must ensure that our custom component behaves and looks correctly in all these cases. In particular, a common issue that you may have already faced, when using custom components retrieved from blogs like mine, is when you override only a few style properties using your CSS stylesheet leading to a half-styled component!2

So, here are two different options that address our constraints:

When styling your custom components, don’t forget to use the Flex Style Explorer that helps a lot to generate CSS style definitions or to check the visual impact of style property changes (refer to the Blogagic Flex Tool Box).

Take also a look at the Flex CSS basics section below in case you wouldn’t yet be fully comfortable with cascading styles.

Styling using the StyleManager

Styling a Flex Custom Component means three things:

Defining custom styles

You can easily add custom styles to your Flex custom components by adding Style metadata tags above your class definition:


// Use the [Style] metadata tag to define custom styles
//
// <MyCustomStyleName>: name of custom style
// <StyleType>: type of the custom style (Number, String, Color, Array,
//				mypackge.MyClass, ...)
// 				When a style property is an Array, add the arrayType
//				property to define the type of the array elements.
// <StyleFormat>: format of the custom style (Length, Color, Time, Boolean,
//				Array, File, String, Object, Number, uint, int, ...)
// inherit: if yes, it means that children of the component inherit the style
// property; if no, they won't.

[Style(name="<MyCustomStyleName>",type="<StyleType>",format="<StyleFormat>",
	inherit="<yes|no>")]

public class MyCustomComponent extends UIComponent
{

I put some comments in the above code describing the Style metadata, for a complete description, read the Style metadata tag from Adobe LiveDocs.

Providing default values for style properties

Default values for style properties can be set using setStyle() but as mentioned in the example on setStyle() usage, style definition can lead to performance issues in Flex applications that are, for example, setting styles in constructors.

So the best way to define your styles is by using a custom CSSStyleDeclaration class and to instantiate it only once, whenever the first instance of your custom component is created.

This can be achieved by creating a private static function classConstruct() that is called through a private static variable initialization as illustrated below:

// static variable to trigger classConstruct when class is initialized
private static var classConstructed:Boolean = classConstruct();

// private static method used to initialize styles
private static function classConstruct():Boolean {
	return true;
}

In this classConstruct() method, we check if a CSSStyleDeclaration already exists for our component or not (it can exist if defined in a CSS stylesheet that has been loaded).

If there is no CSSStyleDeclaration available, we create it and declare an inline function providing the default values for all our style properties.

If there is a CSSStyleDeclaration available, we “parse” it to ensure that there is no missing default value for one of our style properties3.

Here’s how looks the complete classConstruct() method:

// Define static const for style default properties:
// This eases the style default value changes since each default value
// is used twice in the classConstruct() method.
//
// Template:
// private static const default<StyleProperty>:<StyleType> = <StyleDefaultValue>
//
// Examples:
private static const defaultFillColors:Array = [0xff0000, 0x00ff00];
private static const defaultFontSize:uint = 14;

// Styles initialization
private static function classConstruct():Boolean {
	// Check if a CSSStyleDeclaration exists for the component
	var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration("MyComponent");

	if (!style) {
		// If not, create a new one
		style = new CSSStyleDeclaration();

		// and set style default values using an inline function
		style.defaultFactory = function():void {
			// Template:
			// this.<myStyle> = <styleDefaultValue>;
			//
			// Examples:
			this.fillColors = defaultFillColors;
			this.fontSize = defaultFontSize;
			// Preferred to this.fillColors = [0xff0000, 0x00ff00];
	 	};

		// Assign the style declaration
		StyleManager.setStyleDeclaration("MyComponent", style, true);
	}
	else {
		// Ensure that default values exist for all our style properties
		// Template:
		// if (style.getStyle("styleProperty") == undefined) {
		//     style.setStyle("styleProperty", styleDefaultValue);
		// }
		// Example:
		if (style.getStyle("fillColors") == undefined) {
			style.setStyle("fillColors", defaultFillColors);
		}
		if (style.getStyle("fontSize") == undefined) {
			style.setStyle("fontSize", defaultFontSize);
		}
	}
	return true;
}

Managing Style Changes by implementing styleChanged()

Managing style changes means overriding the styleChanged() method. In this method, check whether one of the component style properties is concerned by the style change and update the component accordingly. As mentioned in Flex Component Life Cycle, it’s good practice to use dirty flags in styleChanged() and to make the real component updates in updateDisplayList().

Here’s an example of a basic styleChanged() method:

// Override the styleChanged() method to detect changes in styles
override public function styleChanged(styleProp:String):void {
	super.styleChanged(styleProp);
	// Check if the style is one of ours
	// Template:
	// if (styleProp == "<StyleName>") {
	//     styleDirtyFlags = true;
	//     invalidateDisplayList();
	// }
	//
	// Example (style changes can be grouped as here depending on the
	// component details):
	if ((styleProp == "fillColors") || (styleProp == "fillAphas")) {
		styleDirty = true;
		invalidateDisplayList();
	}
}

// Take style changes into account just before rendering the component
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
	super.updateDisplayList(w, h);

	// Redraw gradient fill only if style changed
	if (styleDirty) {
		var fillColors:Array = getStyle("fillColors");
		var fillAlphas:Array = getStyle("fillAlphas");

		var g:Graphics = graphics;
		g.clear();
		g.beginGradientFill(GradientType.LINEAR, fillColors, fillAlphas, [0x00, 0xFF]);
		g.drawRect(0, 0, unscaledWidth, unscaledHeight);
		g.endFill();

        // Reset dirty flag (don't forget this!)
		styleDirty = false;
	}
}

Styling using a defaults.css stylesheet file

When distributing Flex custom components using an SWC archive file, the easiest way of managing styles is by using a defaults.css stylesheet file.

The defaults.css stylesheet file is implicitly loaded by Flex and applied during the compilation of applications. Embed a defaults.css4 stylesheet file in your SWC and Flex will automatically manage it! Each SWC can have its own defaults.css stylesheet file5, Flex takes care of “merging” them when compiling the application.

By the way, the defaults.css stylesheet is the mechanism used by Flex, there is such a file in the framework.swc that we all use. This is where are stored style definitions for the global class selector and type selector of most of the Flex components. You can find it under “<SDK directory>/frameworks/projects/framework/defaults.css“.

If you embed a defaults.css file in your SWC, you’re almost done; you don’t have to manage your CSSStyleDeclaration using the StyleManager since it’s created automatically when the defaults.css stylesheet file is loaded. Anyway, you still have to implement the styleChanged() method such that your component behaves correctly when any of its styles are changed.

Warning: when changing the defaults.css file, don’t forget to recompile such that your SWC be updated with your latest style definitions.

Flex CSS basics

CSS stands for Cascading Style Sheets. Cascading means that you can apply styles to different levels such as: type, class, instance. For CSS, these levels are called selectors.

The mapping between type, class and instance selectors and Flex is easy:

  • type selector = class name
  • class selector = style name
  • instance selector = instance

Let’s look at an MXML example using an embedded stylesheet to illustrate these principles:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	width="100%" height="100%">

	<mx:Style>
		/* Embedded CSS stylesheets (check Adobe documentation,
		   there are a few restrictions compared to a regular CSS stylesheet)
		 */

		/* Style applicable to all TextInput components */
		TextInput {
			fontSize : 14;
			color: blue;
		}
		/* Custom styles examples */
		.MyBigInputText {
			fontSize: 32;
		}
		.InFocusStyle {
			background-color: yellow;
		}
		.OutFocusStyle {
			background-color: white;
		}
	</mx:Style>

	<mx:Script>
		<![CDATA[
			import mx.controls.ComboBox;
			import flash.events.FocusEvent;

			// Handlers to assign a different style when the
			// TextInput has the focus or not.
			// Any style property can be changed in the above
			// embedded CSS to modify the TextInput behavior
			// when it grabs the focus (changing the size font
			// for example)
			private function onFocusIn(event:FocusEvent): void {
				myDynamicTextInput.styleName = "InFocusStyle";
 			}
			// On focusOut, go back to the regular style (OutFocusStyle)
			private function onFocusOut(event:FocusEvent): void {
				myDynamicTextInput.styleName = "OutFocusStyle";
			}
		]]>
	</mx:Script>

 	<mx:VBox x="10" y="10">
	 	<mx:TextInput text="Enter your input here"/>
	 	<mx:TextInput text="or here if you prefer my size"
	 		styleName="MyBigInputText"/>
	 	<mx:TextInput text="or here if you like colors"
	 		id="myDynamicTextInput"
	 		focusIn="onFocusIn(event)" focusOut="onFocusOut(event)"/>
 	</mx:VBox> 	

</mx:Application>

For more details on CSS selectors, check the CSS Advanced Selectors section of the Adobe Flex SDK documentation.

Reminder: position and size of Flex components can’t be defined using CSS stylesheets6.

Back to Styling Flex Custom Components options.

Setting Styles – examples

From MXML using tag attributes

Component style properties can easily be set using MXML tag attributes as shown in these examples:

<!-- fontSize and color style properties defined directly in MXML -->
<!-- Use this only if the defined properties are specific to this component instance -->
<mx:Button id="fancyBtn" fontSize="32" color="#006600" label="Like Big Green buttons?" />

<!-- assign a Style to the component using the styleName property -->
<!-- the assigned style can be defined in a CSS stylesheet -->
<mx:TextInput text="I'm looking good!" styleName="FancyTextInputStyle"/>

<!-- if a CSS definition exists for Button, it will be applied to this button -->
<mx:Button label="One more button"/>

Using MXML tag attributes to style a component is good when you want to style something quickly. The main drawback is that if you want to apply your style properties to other instances of the component, you have to copy and paste the tags in multiple places; if later, you want to change any of those style properties, you’ll have to update all these places.

Note: styling with inline MXML tags should be avoided when developing custom components that you plan to share with other Flex developers.

Back to Styling Flex Custom Components options.

From ActionScript using setStyle()

When creating components from ActionScript, you can define their style properties by using the setStyle() method. Be warned that setStyle() is known to be resource intensive.

// Create a red button
var btn:Button = new Button();
btn.setStyle("color", 0xff0000);

// Create a button that looks nice
var btn:Button = new Button();
btn.styleName = "NiceButtonStyle";	// Style defined in CSS

Note: initializing styles with setStyle() in a component’s constructor must be avoided. It’s better to Style using the StyleManager instead.

Back to Styling Flex Custom Components options.

Using an embedded CSS stylesheet

Styling by using CSS stylesheets is the easiest way since it decouples the styling activity from the development activity. Anyway, it can sometimes be convenient to use an embedded stylesheet (if you don’t want to expose your component styles to other developers for example).

Embedding a CSS stylesheet just means putting it between <mx:Styles> tag in an MXML file. In case you’d change your mind later, it’d be very easy to copy and paste the section in an CSS stylesheet file and to load it as described in the below section on Using an CSS stylesheet file.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
    width="100%" height="100%">

	<mx:Style>
		/* Embedded CSS stylesheets (check Adobe documentation,
		   there are a few restrictions compared to a regular CSS stylesheet)
		 */

		/* Style applicable to all TextInput components */
		TextInput {
			fontSize : 14;
			color: blue;
		}
		/* Custom style example */
		.MyBigInputText {
			fontSize: 32;
		}
	</mx:Style>

 	<mx:VBox x="10" y="10">
	 	<mx:TextInput text="Enter your input here"/>
	 	<mx:TextInput text="or here if you prefer my size"
	 		styleName="MyBigInputText"/>
 	</mx:VBox>
</mx:Application>

Even if it’s more reusable than the inline styling discussed above, managing one script block per MXML file can quickly become a mess and doesn’t help to make styles consistent across multiple components.

Note: styling with embedded CSS stylesheets should be avoided when developing custom components that you plan to share with other Flex developers.

Back to Styling Flex Custom Components options.

Using a CSS stylesheet file

Using a CSS stylesheet file is the most common way of styling Flex application.You just have to load the stylesheet in the application7.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
    width="100%" height="100%">

	<!-- Load the CSS stylesheet file -->
	<mx:Style source="assets.styles.css" />

 	<mx:VBox x="10" y="10">
		<!-- The components are styled using the loaded CSS stylesheet -->
	 	<mx:TextInput text="Enter your input here"/>
	 	<mx:TextInput text="or here if you prefer my size"
	 		styleName="MyBigInputText"/>
 	</mx:VBox>
</mx:Application>

Note: this is the best method for styling when developing custom components that you plan to share with other Flex developers. It also eases default style values update and maintenance of custom components.

Don’t forget that the CSS stylesheet file is embedded in your SWF (meaning it can’t be modified once the application is deployed). It would often be nice to rely on an External CSS stylesheet file (not embedded in the application) that would be loaded at runtime.

Loading a CSS stylesheet file during run time is possible but this seems not as straightforward as we could expect. I never tried so I am of no help for now :-) It seems that it can be achieved by using CSS files compiled into a SWF file or CSSLoader developed by Ruben Swieringa.

Back to Styling Flex Custom Components options.

List of footnotes:
  1. Best is very personal. If you use another method, it doesn’t mean you’re doing bad! These are just my two preferred ways of applying style to my custom components and some of the reasons they are. []
  2. Usually because overriding only a subset of the component styles from a CSS stylesheet “removes” default values of all the non overridden ones. []
  3. This part is sadly often missing from custom components provided on Flex blogs []
  4. You can’t choose the file name, it must be defaults.css. It must be placed in the top-most directory of the SWC (directly under the src directory). []
  5. Only one defaults.css file is supported per SWC, so it must contain styles of all components that are part of the SWC archive. []
  6. x, y, width and height are properties not styles. []
  7. You should try to limit the number of stylesheets used in an application, and set the stylesheet only at the top-level document in the application (the document that contains the <mx:Application> tag). If you set a stylesheet in a child document, unexpected results can occur. []
VN:F [1.9.3_1094]
Rating: 5.0/5 (8 votes cast)
Styling Flex Custom Components, 5.0 out of 5 based on 8 ratings
  1. No comments yet: be the first commenter!
  1. July 26th, 2010 at 08:36 | #1
Put ActionScript or MXML code snippets between tags: [as3][/as3]
You can also resize the comment area by dragging the bottom right corner.

Bad Behavior has blocked 306 access attempts in the last 7 days.