For Flex 2.0 Beginners - Use the mx:States and mx:ViewStack Tags To Change The Application's View
Introduction:
As a new Flex 2.0 developer coming from using HTML, JavaScript, CSS, DHTML, and ColdFusion, how to design a Flex application was confusing. HTML, even with AJAX, is primarily a page-oriented environment. If I needed to significantly change what the users sees, I would usually have the user go to a new web page. Most HTML-based applications are a series of connected web pages.
In Flex, there is not the concept of a page. Rather, Flex has several different ways for you change the "view" of your application. In this brief tutorial for beginners, I'll introduce two Flex controls: mx:States and mx:ViewStack. These two controls can be used together to change what your users see on screen in your Flex application.
Though, the Flex 2.0 Developer's Guide contains several examples of how to use mx:States and mx:ViewStack, there are not many examples of how to use the two controls together. I think in a more complex Flex application, you're likely to use both controls.
Please note, I'm a Flex 2.0 beginner also. I've built some Flex 2.0 applications and have a good understanding of how to use most of the Flex controls and how to connect a Flex application to a ColdFusion backend. But much of my Flex 2.0 knowledge comes either from reading the documentation or discovery learning through trial-and-error. If you have a better way to use these controls, please post a comment with a link to some good examples. My primary goal in my blog is to help myself and others learn how to use Flex and ColdFusion.
References:
Flex 2.0 Developer's Guide, Chapter 27, Using View States
Flex 2.0 Developer's Guide, Using Transitions
Flex 2.0 Developer's Guide, Chapter 16, ViewStack Navigator Container
Flex 2.0 Developer's Guide, Using Behaviors
Flex 2.0 Language Reference, SetEventHandler
You can view my example application here (right click to read the source code). I've commented the source code, so between the comments and the explanations below you should be able to follow what I did.
Changing the State
My application starts with a simple login form. However, if the user is not already registered, I need a way for him to register and then login. Since the information on the registration form includes what is on the login form, I just need to make some minor changes and additions to the login form to change its "state" to a registration form.
The mx:States tag can be used to add or remove controls from a "base" state. You can also change the properties of a control. In my example, the base state is shown when the user first launches the application. The base state is a simple login form. The user can enter his username and password, press the login button, and the program will log him in. However, if the user needs to register, I've provided a Need to Register link button. When the user clicks on that button, I change the "state" of the panel that is holding the login form.
<!-- The Application class states property defines the view states. -->
<mx:states>
<!--define what needs to be added/removed when showing the register
state-->
<mx:State name="register" id="register">
<!--change the height of the panel-->
<mx:SetProperty target="{loginPanel}" name="height" value="300" />
<!-- add some additional form elements to the login form-->
<mx:AddChild relativeTo="{loginForm}" position="firstChild" creationPolicy="all">
<mx:FormItem id="lastName" label="Last Name:">
<mx:TextInput/>
</mx:FormItem>
</mx:AddChild>
The click event of the registerLink linkButton calls function changeState. In function changeState, I tell the application to set the currentState equal to register. Under the mx:States tag I've created an mx:State with an id of register. Inside this mx:state tag, I change the height of the loginPanel to 300 by using the mx:SetProperty tag. I then add some additional controls using the mx:AddChild tag. I also change the label property of the loginButton to have the value of Register and also change the loginButton's click event handler to be a different function (see mx:SetEventHandler). All of these changes will be made to the base state (the base state is the view of my application that appears when the program is first launched).
So when the user clicks on the Need to Register link, all the commands defined by the tags in my register state will be executed. In addition to defining this new state, I've defined an effect to occur when the application transitions to the register state. Using the mx:transition tag, I defined the Wipe Down effect to occur whenever the state of my application changes from the base state to the register state.
<mx:transitions>
<!-- Define a transition for changing from the base state to the register state.-->
<mx:Transition id="toRegisterState" fromState="*" toState="register">
<mx:WipeDown target="{loginForm}" duration="1000" />
</mx:Transition>
I used the mx:states tag to make relatively minor changes to the application's appearance. If I need to make a major change, for example, all new controls, then I've found it easier to use the ViewStack tag. In my example, when the user logs in, I need to make a complete change to the view.
Changing The View
After the user successfully logs in, I want to show the user a completely new view of my application. This view would have new controls, layout, etc and would be completely different from the login form that is my base state. Though I could use a new mx:state tag to achieve this new look, using the ViewStack container is simpler.
mx:ViewStack is a navigator container. Views of your application can be "stacked" on top of each other and the user can only see and interact with the top view on the stack. After you specify an mx:ViewStack tag, a view will be created for each child container. In my example, I have defined three mx:panel tags: loginPanel, mainApplication, and secondaryApplication. So my mx:ViewStack has three child containers. The default child displayed will be the first one, loginPanel, which is also the view for my base state.
<mx:ViewStack id="appViews" width="100%" height="100%">
<!--since this panel is the first child of the ViewStack it will be the default base
state and will be what appears when the user starts the application-->
<mx:Panel title="Login" id="loginPanel" horizontalScrollPolicy="off"
verticalScrollPolicy="off" layout="absolute" width="300" height="175">
</mx:Panel>
<!--The application will switch to this ViewStack child after the user logs in-->
<mx:Panel title="Main Application View" width="100%" height="100%" id="mainApplication"
showEffect="mainApplicationWipeLeft" hideEffect="mainApplicationWipeRight">
</mx:Panel>
<!--The application will switch to this ViewStack child if the user clicks on the button in the
mainApplication panel-->
<mx:Panel title="Secondary Application View" width="100%" height="100%" id="secondaryApplication"
showEffect="secondaryApplicationFadeIn">
</mx:Panel>
You can determine when to change the view that is on the top. In my example, after the user successfully logs in, I want a completely new view. So in function login, I specify that the ViewStack control (named appViews) should make the selected child named mainApplication visible (move it to the top of the stack). On the mainApplication panel, I would have all my new controls. In my example, I use buttons to give the user the ability to change the view to the secondaryApplication panel or to logout and return to the loginPanel.
I've also defined some effects (behaviors) to play when these panels become visible or hidden. You can specify an effect to occur by using the showEffect and hideEffect attributes of the mx:panel.
Summary:
Using a combination of mx:States and mx:ViewStack can provide you with powerful tools to change the "view" of your application. My example is simple, but by studying the references above you can use these two Flex controls together to create complex Flex applications. I hope this brief tutorial and my example will help you understand better how to make the transition from designing an HTML page-based application to designing a Flex 2.0 application.


You are right there is documentation around, i still think people coming from a traditional web based layout though ( new content = new page ) struggle a little with how to move through their application and which options are appropriate.
This shows clearly how to / advantages without worrying about the other bits and peices .. clear and concise :-)
You stuff is really informative. Been using your site as a learning tool for Flex. I was wondering if you had any ideas to change a viewstate via a combobox? Just curiuous. Any help/feedback is welcomed. Thanks again. Keep up the good work!
Thanks.
I've not done this but try using ApplicationControlBar that contains a combo box. On the combo box change event, have the function select a new child for the view stack that matches the label of the combo box.
I also use your site often to learn more about flex. So to start off a big thank-you!
how about changing the view of a stack from within a view?
One way to solve your issue would be to pass a reference to the ViewStack to your custom component. Then our custom component could use that reference to change the ViewStack's selected child. See my blog entry on exposing properties for child components.
But I bet there is an easier way to get a reference to the ViewStack. I'll research this more and post what I can find. Again, you may also want to post your question on the Yahoo! FlexCoders group as they have much more expertise then I.
Take a look at:
http://www.brucephillips.name/blog/index.cfm/2007/...
where I actually register the user. You'll see that the ActionScript functions just refer to the form fields by the id value (eg, email.text) even if those form fields are added in a state change.
I suspect you're not refering to the id value correctly. Anyway take a look at the above example's code.
<mx:Sequence id="slideUpOut">
<mx:Move yBy="-400" duration="1000"/>
</mx:Sequence>
<mx:Sequence id="slideUpIn">
<mx:Move yFrom="500" yTo="0" duration="1000"/>
</mx:Sequence>
<mx:ViewStack id="appViewStack" left="0" right="0" top="0" bottom="0">
<vw:Login id="appLogin" formSubmitted="enterApp()" name="appLogin" hideEffect="{slideUpOut}" />
<vw:Home id="appHome" showEffect="{slideUpIn}" />
</mx:ViewStack>
See:
http://livedocs.adobe.com/flex/2/docs/00000940.htm...
and
http://livedocs.adobe.com/flex/2/langref/mx/effect...
I've followed this tutorial and it works great thanks, but i'm stuck when it comes to practice. Most my 'pages' are components in a viewstack as well as the login page. and as there are usually a login and signup button -how would the user click from one component in a viewstack to another component's state (ie. your register state?) and further change the state back to base when u click onwards and come back to that compenent's view?
Always a pleasure to be on your site. I am facing an issue with a ViewStack's children showEffect and hideEffect behaviors when using certain effects (namely Zoom and Blur) - Does anyone notice that when applying certain effects to a ViewStack's children on hide and show that the final state of the newly selected child blinks on screen for a moment before the effect plays?
So if I blur out Child A and then blur in Child B, Child B flickers for a moment in its "in focus" display state before the blur effect happens.
Seems to be an ongoing issue.
Sorry to be so thick
Download that zip file and then open it up. In this example there is one .mxml file since all the code is contained in that one file.
If you want to run this file in your own Flex project: Create a new Flex project in Flex Builder (you can name it statesTest to match the single mxml file name or you can use your own name).
Copy the statesText.mxml file into your project's root folder. Now you can run that file in Flex Builder.
You may want to check out the 30 days of Free Flex Training being offered by Total Training. See: http://www.totaltraining.com/Store/online_adobe_lo...
You'll get lots of practice on creating Flex projects using saved code files (there are several different ways to do this).
pls give me a good solution...........
thanks in advance
Should the levels state be inside a panel or some other contianer.
====================================================
<mx:WipeRight duration="1000" id="wipeIn" />
<mx:states>
<mx:State name="{ModelLocator.INIT}">
<mx:AddChild>
<view:SignInPanel id="signInPanel" horizontalAlign="center" verticalAlign="middle" />
</mx:AddChild>
</mx:State>
<mx:State name="{ModelLocator.PLAY}">
<mx:RemoveChild id="removeSignInPanel" target="{signInPanel}" />
<mx:AddChild>
<view:Levels id="levels" width="100%" height="100%" />
</mx:AddChild>
</mx:State>
<mx:transitions>
<mx:Transition id="fadeSignInOut" fromState="{ModelLocator.INIT}" toState="{ModelLocator.PLAY}">
<mx:Sequence>
<mx:Move target="{signInPanel}" xTo="5000" duration="2000" />
<mx:RemoveChildAction target="{signInPanel}" />
<mx:AddChildAction target="{levels}" />
</mx:Sequence>
</mx:Transition>
</mx:transitions>
====================================================
Good Tutorial indeed ...
But if I add a ButtonBar by providing "ViewStack's" id as a datasource .. it displays all the components viz Login,MainApplication and SecondaryApplication in the whole browser.
How to avoid that by displaying first the login component and then rest of the two after successful login with the help of ButtonBar or any Nav. Control.
Thanks
-jai
How can we navigate from one flex page to another based on the input.
Thanks,
Laskan