In previous posts in the series we discussed new features in Flex 4 that are basic in nature (namespaces, an introduction to the new Spark components architecture and the new mxml tags to name a few).
In the next few posts we will discuss the more interesting stuff new with Flex 4 like FXG, states, layouts, effects and skinning.
So, without further ado, View States!
View states let you modify how a component looks and the data it shows, usually as a result of user interaction. A state change can be rearranging children of a container, adding or removing controls, show more or less data, wizards are often implemented with states etc. Transitions control how these view changes looks (spoiler – transitions is our next series post topic).
Basically, you define a default view state and then define a set of overrides that modify the default view state. You can add, remove or reparent children, modify styles or property values, or define state-specific event handlers.
Note, that when using Flex 3 view states were optional. You didn’t have to use them and could write entire applications without using them. View states are a must with Flex 4 when defining skins and item renderers for Spark components, so listen close 🙂
I attached source code examples at the bottom of the post.
All the properties, styles, event handlers and children you define in any component are mapped to it’s default view state. Each additional defined view state overrides the default view state. These overrides lets you change the properties, styles and event listeners and add, remove or reparent children.
To create view states, there are a few simple rules to follow. Consider the following example:
<s:Application> <s:states> <s:State name="State1"/> <s:State name="State2"/> <s:State name="State3"/> </s:states> <!-- Application definition. --> </s:Application>
The <s:states> tag must be defined at the component (or application) root tag level and all view states should be defined within it’s scope. Use the name property of the State object to specify it’s identifier. The <s:states> tag essentially defines an array of states where each item corresponds to a view state State object.
Since all spark components extend UIComponent, changing view states for mx or spark components is done the same way- you set the component’s currentState property to the value of a view state name property. Note, that the component’s default state is defined as the first state defined in the <s:States> tag, and as such, it is the default value of the currentState property.
To extend the example above, we add two buttons that modify the component’s currentState property to change the view state:
<s:Application> <s:states> <s:State name="State1"/> <s:State name="State2"/> <s:State name="State3"/> </s:states> <s:Button id="b1" label="Change to State 1" click="currentState='State2';"/> <s:Button id="b2" label="Change to the default" click="currentState='State1';"/> <!-- This also works <s:Button id="b2" label="Change to the default" click="currentState='';"/> --> </s:Application>
OK, great. We defined the view states and we know how to change from one to another.
Now what? How do we override default behavior defined in the default view state like properties, styles and listeners?
I’m glad you asked 🙂
The new dot operator to the rescue! We use this operator to define state-specific property or style values. It uses the propertyOrStyleName.stateName format.
Consider the following:
<s:Button id="b3" label="Default State" label.State2="New State" click="defaultButtonEventHandler" click.State2="state2ButtonEventHandler"/>
The value of the label property qualified by “State2” specifies the value for the property in that view state. Event listener is defined the same way.
The unqualified property definition, the one that omits the dot notation, defines the value of the property for all view states where you do not explicitly define an override. You should not specify an override for every property, style or listener for all view states. Only specify an override for a view state you want the default changed, and only for the changed elements.
OK, so now we know how to specify default view state values and how to override them for specific view states. But what if I want to display different controls in different states? Maybe remove a button from view and add another button to view?
In this case we use the includeIn and excludeFrom attributes to specify in which states a component is included or not. It’s important to know that they are mutually exclusive and defining both of them in a single MXML tag produces an error. Both take a comma delimited list of view state names explicitly declared in the <s:states> Array.
includeIn and excludeFrom are legal attributes on any MXML object in an MXML document, with some exceptions:
- The root tag of an MXML document.
- Tags that represent properties of their parent tag.
- Descendants of the <fx:XML>, <fx:XMLList>, or <fx:Model> tags.
- Any language tags, such as the <fx:Binding>, <fx:Declarations>, <fx:Metadata>, <fx:Script>, and <fx:Style> tags.
In the next post we’ll discuss more about view states.
Specifically, we’ll talk about
- Changing the parent of a controller
- How to control when to create added children
- Caching of objects created in a view state
- Defining view states in custom components and using them in item renderers
- Integrating view states with the browser manager
Sample code (right click + save as…)