Create and apply view statesThe properties, styles, event handlers, and components that you define for an application or custom component specify its default view state. Any additional view state specify changes to the default view state. For each additional view state, define overrides of the default view state. Overrides modify the properties, styles, and event handlers for a component, add a component to a view state, remove a component from a view state, or change the parent container of a component in a view state. Creating view statesConsider the following when you define a view state.
The following MXML code shows this structure: <s:Application>
<!-- Define the view states.
The <s:states> tag can also be a child tag of
the root tag of a custom component.
-->
<s:states>
<s:State name="State1"/>
<s:State name="State2"/>
<s:State name="State3"/>
.
.
</s:states>
<!-- Application definition. -->
.
.
</s:Application>
The default view state is defined as the first view state in the <s:states> Array. An application uses the default view state when it loads. The name of the default view state is not reserved, so it is not required to be "default". Changing view stateThe UIComponent class defines the currentState property that you use to set the current view state. When the application starts, the default value of the currentState property is the name of the first view state defined by the <s:states> tag. In the next example, you use a Button control to set the currentState property of the Application object to "State1" or "State2", the names of a view state specified by the <s:State> tag: <s:Button id="b1" label="Change to State 1" click="currentState='State2';"/> <s:Button id="b2" label="Change to the default" click="currentState='State1';"/> The second button in the previous example sets the current state to "State1" so that you can switch back to the default view state from "State2". You can also set the currentState property to an empty String to set it to the default state, as the following example shows: <s:Button id="b2" label="Change to the default" click="currentState='';"/> You can change a component’s view state by calling the setCurrentState() method of the UIComponent class. Use this method when you do not want to apply a transition that you have defined between two view states. For more information on transitions, see Transitions. Setting properties, styles, and events for a view stateDefine state-specific property and style values by using
the dot (.) operator with any writable MXML tag attribute. The dot
notation has the following format:
propertyOrStyleName.stateName For example, specify the value of the label property
of a Button control for the default view state and for one additional
view state, as the following example shows:
<s:Button label="Default State" label.State2="New State"/> The value of the label property qualified by “State2” specifies the value for the property in that view state. 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. Do not define an override for every property, style, and event for all view states. Only define the override for those view states where you want to change the value of the element. You can also use child tags with the dot notation to define property overrides, as the following example shows for the b1 button control: <?xml version="1.0"?>
<!-- states\StatesSimpleChildTags.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:states>
<!-- Define the new view states. -->
<s:State name="default"/>
<s:State name="NewButton"/>
</s:states>
<s:VGroup >
<s:HGroup>
<!-- Disable Button in the NewButton view state. -->
<s:Button id="b1">
<s:label>Click Me</s:label>
<s:label.NewButton>Disabled</s:label.NewButton>
<s:enabled.NewButton>false</s:enabled.NewButton>
</s:Button>
<!-- Add a new child control to the VBox. -->
<s:Button id="b2" label="New Button"
includeIn="NewButton"/>
</s:HGroup>
<!-- Define Button control to switch to NewButton view state. -->
<s:Button label="Change to NewButton state"
click="currentState='NewButton';"/>
<!-- Define Button control to switch to default view state. -->
<s:Button label="Change to default view state"
click="currentState='default';"/>
</s:VGroup>
</s:Application>
To clear the value of a property in a view state, set the property
to the value @Clear(), as the following example
shows:
<s:Button color="0xFF0000" color.State1="@Clear()"/> For a style property, setting the value to @Clear() corresponds to calling the clearStyle() method on the property. Use the dot operator to change the event handler for a specific view state, as the following example shows. In this example, the handler for the click event for button b1 is set based on the view state: <?xml version="1.0"?>
<!-- states\StatesEventHandlersSimple.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:states>
<s:State name="default"/>
<s:State name="logout"/>
</s:states>
<s:VGroup >
<s:Button id="b1" label="Click Me"
click="ta1.text='hello';"
click.logout="ta1.text='goodbye'"/>
<s:TextArea id="ta1" height="100" width ="50%"/>
<s:Button label="Default State"
click="currentState='';"
enabled="false"
enabled.logout="true"/>
<s:Button label="Logout State"
click="currentState='logout';"
enabled="true"
enabled.logout="false"/>
</s:VGroup>
</s:Application>
Adding or removing components for a view stateUse the includeIn and excludeFrom MXML attributes to specify the set of view states in which a component is included, where:
The following example uses view states to add components to the application based on the current state: <?xml version="1.0"?>
<!-- states\StatesSimpleIncExc.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:states>
<s:State name="default"/>
<s:State name="addCheckBox"/>
<s:State name="addTextInput"/>
<s:State name="addCheckBoxandButton"/>
</s:states>
<s:HGroup >
<!-- Included in the addCheckBox and addCheckBoxandButton view states. -->
<s:CheckBox id="myCB" label="Checkbox"
includeIn="addCheckBox, addCheckBoxandButton"/>
<!-- Included in the addTextInput view state. -->
<s:TextInput id="myTI"
includeIn="addTextInput"/>
<!-- Included in the addCheckBoxandButton view state. -->
<s:Button id="myB"
includeIn="addCheckBoxandButton"/>
<!-- Exclude from addTextInput view state. -->
<s:TextArea text="Exclude from addTextInput"
excludeFrom="addTextInput"/>
</s:HGroup>
<s:HGroup>
<s:Button label="Add CheckBox"
click="currentState='addCheckBox'"/>
<s:Button label="Show Textinput Only"
click="currentState='addTextInput'"/>
<s:Button label="Add CheckBox and Button"
click="currentState='addCheckBoxandButton'"/>
<s:Button label="Default"
click="currentState='default'"/>
</s:HGroup>
</s:Application>
You can specify the includeIn and excludeFrom attributes
on any MXML object within an MXML document, with the exception of
the following tags:
Restriction on modifying container children when using view statesWhen you use view states to control the children of a container, do not add or remove container children, or change the order of children in the container, at runtime. For example, the following container defines a Button control that appear only in State2: <s:Group id="myGroup">
<s:Button/>
<s:Button includeIn="State2"/>
<s:Button/>
</s:Group>
The view states infrastructure relies on the structure of the container as defined by the MXML file. Changing the child order of the container at runtime can cause your application to fail. Therefore, do not call the addElement(), removeElement(), setElementIndex() method on the Group container at runtime, or any other method that changes the child order of the container. Changing the parent of a componentA view state can change the parent container of a component. Changing the parent container of a component is called reparenting the component. Use the <fx:Reparent> tag to change the
parent container of a component. The <fx:Reparent> tag
has the following syntax:
<fx:Reparent target="targetComp" includeIn="stateName"> The target property specifies the target component, and the includeIn property specifies a view state. When the current view state is set to stateName, the target component becomes a child of the parent component of the <fx:Reparent> tag. You can think of the <fx:Reparent> tag as a placeholder for the component for a specific view state. You can use the <fx:Reparent> tag in any component that can hold a child component, and the child can use the includeIn or excludeFrom keywords. The following example uses the <fx:Reparent> tag
to switch a Button control between two Panel containers:
<?xml version="1.0" encoding="utf-8"?>
<!-- states\NewStatesReparent.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:states>
<s:State name="Parent1"/>
<s:State name="Parent2"/>
</s:states>
<s:HGroup>
<s:Panel id="Panel1"
height="100" width="100"
title="Panel 1">
<s:Button id="setCB" includeIn="Parent1"/>
</s:Panel>
<s:Panel id="Panel2"
height="100" width="100"
title="Panel 2">
<fx:Reparent target="setCB" includeIn="Parent2"/>
</s:Panel>
</s:HGroup>
<s:HGroup>
<s:Button label="Parent 1"
click="currentState='Parent1'"
enabled.Parent1="false"/>
<s:Button label="Parent 2"
click="currentState='Parent2'"
enabled.Parent2="false"/>
</s:HGroup>
</s:Application>
Two <fx:Reparent> tags cannot target the same component for the same view state. That means a component can only have a single parent in each view state. Controlling when to create added childrenWhen you remove a component as part of a change of view state, you remove the component from the application’s display list, which means that it no longer appears on the screen. Even though the component is no longer visible, the component still exists and you can access it from within your application. When you add a component as part of a change of view state, you can either create the component before the first change to the view state, or create it at the time of the first change. If you create the component before the first change, you can access the component from within your application even though you have not yet changed view states. If you create the component when you perform the first change to the view state, you cannot access it until you perform that first change. By default Flex creates container children when they are first required as part of a change of view state. However, if a child requires a long time to create, users might see a delay when the view state changes. Therefore, you can choose to create the child before the state changes to improve your application’s apparent speed and responsiveness. Regardless of when you create a component, the component remains in memory after you change out of the view state that creates it. Therefore, after the first change to a view state, you can always access the component even if that view state is no longer the current view state. The specification of when the child is created is called its creation policy. For more general information on creation policies and controlling how children are created, see Improving startup performance. Use the itemCreationPolicy property to specify the creation policy. The itemCreationPolicy property supports the following values:
The following example uses the Immediate view state to add a Button control named newButtonImmediate. You set the itemCreationPolicy property for this button to immediate to create the button at application startup. Therefore, the application can access it to set its label property before it switches to the Immediate view state. The application also uses the Deferred view state to create the button named newButtonDeferred with the itemCreationPolicy property set to deferred. Therefore, this button is created when you first change to the Deferred view state, and you cannot access it until after the first switch to the Deferred view state: <?xml version="1.0"?>
<!-- states\StatesCreationPolicy.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initButton();">
<fx:Script>
<![CDATA[
// Because the Immediate view state creates the Button control
// at application startup, you can access the control to
// set the label before the first switch
// to the Immediate view state.
public function initButton():void {
newButtonImmediate.label="Immediate Button";
// Uncommenting this line to access the label causes a
// Run Time Exception because newButtonDeferred does not exist yet.
// newButtonDeferred.label="Deferred Button";
}
]]>
</fx:Script>
<s:states>
<s:State name="default"/>
<s:State name="Immediate"/>
<s:State name="Deferred"/>
</s:states>
<s:Panel id="myPanel"
title="Static and dynamic states"
width="300" height="150">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<!-- Create the Button control at application startup. -->
<s:Button id="newButtonImmediate"
includeIn="Immediate"
itemCreationPolicy="immediate"/>
<!-- Create the Button control when you switch to this view state. -->
<s:Button id="newButtonDeferred"
label="Deferred button"
includeIn="Deferred"
itemCreationPolicy="deferred"/>
<!-- Change to the Immediate view state. -->
<s:Button label="Change to Immediate state"
click="currentState='Immediate';"/>
<!-- Change to the Deferred view state. -->
<s:Button label="Change to Deferred state"
click="currentState='Deferred';"/>
<!-- Change to the default view state. -->
<s:Button label="Change to default state"
click="currentState='default';"/>
</s:Panel>
</s:Application>
Controlling caching of objects created in a view stateA change to a view state can cause Flex to create an object. By default, after Flex creates the object, the object is cached indefinitely, even after you switch to another view state. The item is cached even if the destination view state excludes the object. Use the itemDestructionPolicy attribute with the includeIn and excludeFrom attributes configure Flex to completely destroy the object when leaving a view state, including deleting it from the cache. Typically it is more efficient to allow items to be cached because it improves performance when switching back to the view state that created the object, or to a view state that uses the object. However your application might define a view state that is rarely used, and you do not want to allocate memory for caching the object. You can use the itemDestructionPolicy attribute on any object in MXML that supports the includeIn and excludeFrom attributes. The possible values for itemDestructionPolicy are never (default) and auto. The value of never specifies that the object is cached indefinitely. A value of auto means that the object is destroyed when leaving a view state where the object exists. The following example sets the attribute to auto: <s:TextInput includeIn="newTextInput" itemDestructionPolicy="auto"/> Defining view state groupsThe stateGroups attribute of the <s:States> tag lets you group one or more states together. For example, if multiple components appear in the same set of view states, create a view state group that contains all these view states. Then, when you set the currentState property to any view state in the group, the components appears. In the following example, the CheckBox control named myCB appears when you change to any view state in Group1: <?xml version="1.0"?>
<!-- states\StatesSimpleGroups.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:states>
<s:State name="default"/>
<s:State name="addCheckBox" stateGroups="Group1"/>
<s:State name="addTextInput"/>
<s:State name="addCheckBoxandButton" stateGroups="Group1"/>
</s:states>
<s:HGroup>
<!-- Included in the addCheckBox and addCheckBoxandButton view states. -->
<s:CheckBox id="myCB" label="Checkbox"
includeIn="Group1"/>
<!-- Included in the addTextInput view state. -->
<s:TextInput id="myTI"
includeIn="addTextInput"/>
<!-- Included in the addCheckBoxandButton view state. -->
<s:Button id="myB"
includeIn="addCheckBoxandButton"/>
<!-- Exclude from addTextInput view state. -->
<s:TextArea text="Exclude from addTextInput"
excludeFrom="addTextInput"/>
</s:HGroup>
<s:HGroup>
<s:Button label="Add CheckBox"
click="currentState='addCheckBox'"/>
<s:Button label="Add Textinput"
click="currentState='addTextInput'"/>
<s:Button label="Add Group 1"
click="currentState='addCheckBoxandButton'"/>
<s:Button label="Default"
click="currentState='default'"/>
</s:HGroup>
</s:Application>
Example: Login form applicationThe following example creates the Login and Register forms shown in Example: Login form application. This application has the following features:
Note: For an example that adds a transition to animate
the change between view states, see Example: Using transitions with a login form.
<?xml version="1.0"?>
<!-- states\LoginExample.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- The Application class states property defines the view states.-->
<s:states>
<s:State name="default"/>
<s:State name="Register"/>
</s:states>
<!-- Set title of the Panel container based on the view state.-->
<s:Panel id="loginPanel"
title="Login" title.Register="Register">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:Form id="loginForm">
<mx:FormItem label="Username:">
<s:TextInput/>
</mx:FormItem>
<mx:FormItem label="Password:">
<s:TextInput/>
</mx:FormItem>
<mx:FormItem id="confirm" label="Confirm:" includeIn="Register">
<!-- Add a TextInput control to the form for the Register view state. -->
<s:TextInput/>
</mx:FormItem>
<mx:FormItem direction="horizontal">
<!-- Use the LinkButton to change view state.-->
<mx:Spacer width="100%" id="spacer1"/>
<!-- Set label of the control based on the view state.-->
<mx:LinkButton id="registerLink"
label="Need to Register?"
label.Register="Return to Login"
click="currentState='Register'"
click.Register="currentState=''"/>
<s:Button id="loginButton"
label="Login" label.Register="Register"/>
</mx:FormItem>
</mx:Form>
</s:Panel>
</s:Application>
Example: Controlling layout using view states groupsIn this example, you define an application with three Panel containers and three view states, as the following example shows: To change view state, click the Panel container that you want to display in the expanded size. For a version of this example that adds a transition to animate the view state change, see Defining transitions. <?xml version="1.0"?>
<!-- states/ThreePanel.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark" width="400">
<!-- Define the two view states, in addition to the default view state.-->
<s:states>
<s:State name="default"/>
<s:State name="One"/>
<s:State name="Two"/>
</s:states>
<!-- Define the Group container holding the three Panel containers.-->
<s:Group width="100%" height="100%">
<s:Panel id="p1" title="One"
x="0" y="0"
x.One="110" y.One="0"
x.Two="0" y.Two="0"
width="100" height="100"
width.One="200" height.One="210"
width.Two="100" height.Two="100"
click="currentState='One'">
<s:Label fontSize="24" text="One"/>
</s:Panel>
<s:Panel id="p2" title="Two"
x="0" y="110"
x.One="0" y.One="0"
x.Two="110" y.Two="0"
width="100" height="100"
width.One="100" height.One="100"
width.Two="200" height.Two="210"
click="currentState='Two'">
<s:Label fontSize="24" text="Two"/>
</s:Panel>
<s:Panel id="p3" title="Three"
x="110" y="0"
x.One="0" y.One="110"
x.Two="0" y.Two="110"
width="200" height="210"
width.One="100" height.One="100"
width.Two="100" height.Two="100"
click="currentState='default'">
<s:Label fontSize="24" text="Three"/>
</s:Panel>
</s:Group>
</s:Application>
You can optimize this application by using view state groups, as the following example shows: <?xml version="1.0"?>
<!-- states/ThreePanelGroups.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark" width="400">
<!-- Define the two view states, in addition to the default state.-->
<s:states>
<s:State name="default" stateGroups="grpDefaultOne, grpDefaultTwo"/>
<s:State name="One" stateGroups="grpDefaultOne, grpOneTwo "/>
<s:State name="Two" stateGroups="grpDefaultTwo, grpDefaultTwo, grpOneTwo"/>
</s:states>
<!-- Define the Group container holding the three Panel containers.-->
<s:Group width="100%" height="100%">
<s:Panel id="p1" title="One"
x.grpDefaultTwo="0" y.grpDefaultTwo="0"
x.One="110" y.One="0"
width.grpDefaultTwo="100" height.grpDefaultTwo="100"
width.One="200" height.One="210"
click="currentState='One'">
<s:Label fontSize="24" text="One"/>
</s:Panel>
<s:Panel id="p2" title="Two"
x="0" y="110"
x.One="0" y.One="0"
x.Two="110" y.Two="0"
width.grpDefaultOne="100" height.grpDefaultOne="100"
width.Two="200" height.Two="210"
click="currentState='Two'">
<s:Label fontSize="24" text="Two"/>
</s:Panel>
<s:Panel id="p3" title="Three"
x="110" y="0"
x.grpOneTwo="0" y.grpOneTwo="110"
width="200" height="210"
width.grpOneTwo="100" height.grpOneTwo="100"
click="currentState='default'">
<s:Label fontSize="24" text="Three"/>
</s:Panel>
</s:Group>
</s:Application>
Using view state eventsWhen a component’s currentState property changes, the State object for the states being exited and entered dispatch the following events:
The following example uses the enterState and exitState events
to update two TextArea controls with the name of the new state and
of the old state:
<?xml version="1.0"?>
<!-- states\StatesSimpleEvent.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
height="450">
<s:states>
<!-- Define the new view states. -->
<s:State name="default"
enterState="MyEnterTA.text = 'Enter state: default';"
exitState="MyExitTA.text = 'Exit state: default';"/>
<s:State name="NewButton"
enterState="MyEnterTA.text = 'Enter state: NewButton';"
exitState="MyExitTA.text = 'Exit state: NewButton';"/>
</s:states>
<s:VGroup id="g1">
<s:HGroup>
<s:Button id="b1" label="Click Me"
enabled.NewButton="false"/>
<s:Button id="b2" label="New Button"
includeIn="NewButton"/>
</s:HGroup>
<s:Button label="Change to NewButton state"
click="currentState='NewButton';"/>
<s:Button label="Change to default view state"
click="currentState='default';"/>
<s:TextArea id="MyEnterTA"/>
<s:TextArea id="MyExitTA"/>
</s:VGroup>
</s:Application>
|
|