Tải bản đầy đủ (.pdf) (50 trang)

Tài liệu Flash Builder 4 and Flex 4 Bible- P11 ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (919.04 KB, 50 trang )

Chapter 16: Managing Application Navigation
471
recalculated and rendered anew on each visit to the page. The browser offers caching of
image and other assets to speed up this process, but graphical presentation in a Web
page is necessarily limited.
l
HTML and JavaScript aren’t interpreted identically by every Web browser. In fact,
one of the most costly and time-consuming aspects of classic Web application develop-
ment is testing, because you must test your application on each combination of operating
system, browser, and version that you want to support. Some Web application vendors
handle this issue by limiting the platforms on which an application is supported. For
example, Intuit’s QuickBooks Online, while a powerful and reliable Web application, is
supported only on Microsoft Internet Explorer on Windows and Safari on Mac — no
Firefox users allowed!
Understanding Flex Navigation
Navigation in Flex applications is handled at two levels with navigator containers and view states.
The difference between these strategies can be described as one of the amount of visual change
during a move from one presentation to another:
l
Navigator containers. Use these when you want to replace a rectangular region of a Flex
application (a view) with a completely different visual presentation.
l
View states. Use these when you want to modify an existing view, by adding or removing
visual components or by changing components’ properties, styles, or event listeners.
In some cases, either a navigator container or a view state can get the job done, but for the most
part the choice is clear: Use a navigator container to move from one view to another, and use a
view state to change an existing view.
Cross-Reference
Detailed information about view states is available in Chapter 13.
n
Using Navigator Containers


You create a stack of views using one of the navigator containers provided in the Flex framework.
The
ViewStack class is the simplest of these navigator containers. You declare the ViewStack
container as a parent container that nests a collection of view components and displays only one of
its nested views at any given time.
The
ViewStack container doesn’t have any user interface controls that enable the user to select a
current view, so it’s typically controlled either with ActionScript code or with navigator bar com-
ponents that use the
ViewStack as a data provider and dynamically generate interactive compo-
nents to control navigation.
22_488959-ch16.indd 47122_488959-ch16.indd 471 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
472
Declaring a ViewStack in MXML
To create a ViewStack in MXML, declare an <mx:ViewStack> tag set. Then declare each
nested container within the
<mx:ViewStack> tag set. You can nest either pre-built containers
from the Flex framework or your own custom components. The containers you nest within the
ViewStack can be either layout or navigator containers.
New Feature
The ViewStack, TabNavigator, and Accordion navigator containers were originally designed so they
could only contain instances of the original MX container classes such as
VBox, HBox, and Panel. This rule is
enforced via the nested object’s inheritance hierarchy: Each of the components nested directly within a
ViewStack must include mx.core.Container as one of its superclasses. If you nest most Spark compo-
nents directly in a
ViewStack, a type coercion error is generated at runtime when the framework tries to cast
the object as

Container.
To solve this, nest the Spark component inside a new component named NavigatorContent. This container
implements a new interface named
INavigatorContent, making it compatible with the MX navigator con-
tainers. To use Spark containers in a
ViewStack (or in its related navigator containers, TabNavigator and
Accordion), nest them in an instance of NavigatorContent.
n
Each container nested within a navigator container, whether implemented as a ViewStack,
TabNavigator, or Accordion, should have a label property. The label is an arbitrary
String that’s used in many circumstances to describe the container’s purpose to the user. You
don’t always need the
label property, but if you bind the stack to a navigator container that gen-
erates interactive components such as
Buttons, or if you use the TabNavigator or
Accordion containers, the value of each nested container’s label is displayed on the interactive
component that navigates to that child container.
This code creates a
ViewStack with five views or layers:
<mx:ViewStack id=”views”>
<mx:HBox/>
<mx:VBox/>
<mx:Canvas/>
<s:NavigatorContent>
<s:Panel/>
<s:/NavigatorContent>
<views:MyCustomComponent/>
</mx:ViewStack>
The first three views are instances of MX containers, the fourth is a Spark Panel wrapped in
NavigatorContent, and the last is an instance of a custom component that’s extended from a

compatible container component.
Using custom components in a navigator container
The views nested within a navigator container can be defined as custom components in MXML.
As described previously, a custom component that’s nested in a navigator container must extend
22_488959-ch16.indd 47222_488959-ch16.indd 472 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
473
either the Spark NavigatorContent component or one of the MX container classes. These
include
HBox, VBox, Canvas, Panel, Form, and others.
The custom component in Listing 16.1 displays a
Label control and a DataGrid wrapped in a
NavigatorContent container.
LISTING 16.1
A custom component suitable for use in a navigator container
<?xml version=”1.0” encoding=”utf-8”?>
<s:NavigatorContent xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
width=”400” height=”300”>
<s:layout>
<s:VerticalLayout horizontalAlign=”center”/>
</s:layout>
<s:Label text=”Author List” styleName=”logo”/>
<mx:DataGrid>
<mx:columns>
<mx:DataGridColumn dataField=”title” headerText=”First Name”/>
<mx:DataGridColumn dataField=”price” headerText=”Last Name”/>
</mx:columns>

</mx:DataGrid>
</s:NavigatorContent>
On the Web
The code in Listing 16.1 is available in the Web site files as views/Authors.mxml in the chapter16 proj-
ect. View components named
Books.mxml and ShoppingCart.mxml are also used in these examples.
n
Creating a ViewStack in Design mode
You can use Flash Builder’s Design mode to visually create a ViewStack and its nested views. As
described previously, each of the nested views must be a container, as an instance of either a Flex
framework container class or a custom component that includes the
Container class in its inher-
itance hierarchy.
Note
Flash Builder’s Design mode refers to the layers of a ViewStack as panes, and the documentation sometimes
refers to them as panels. These terms refer to the nested view containers within the
ViewStack.
n
On the Web
The steps in this section assume that you’ve downloaded the files from the Web site and imported the
chapter16 project.
n
22_488959-ch16.indd 47322_488959-ch16.indd 473 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
474
Follow these steps to create a ViewStack in Design mode:
1. Open BookStore.mxml from the chapter16 project. Notice that the application
already has an instance of a custom
Header component and a few layout settings:

<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>
<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header/>
</s:Application>
2. Run the application. As shown in Figure 16.1, you should see that the Header compo-
nent displays an image, some text, and a background image.
3. Return to Flash Builder, and switch to Design mode.
FIGURE 16.1
The starting application with a custom Header component
22_488959-ch16.indd 47422_488959-ch16.indd 474 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
475
4. Look in the Components view’s Navigators section, and drag a ViewStack into the
application below the header. As shown in Figure 16.2, the
ViewStack is represented
visually by a rectangular outlined area and a toolbar with
+ and – buttons to add and
remove views, and
< and > buttons to navigate from one view to the next.
FIGURE 16.2
A starting ViewStack

Previous
view
Add view
Next view
Remove view
The ViewStack
5. Click the + button to add a new view to the ViewStack. As shown in Figure 16.3,
the Insert Pane dialog box prompts you to select a component to instantiate as a layer of
the
ViewStack. The list of available components includes all containers from the Flex
framework and all the application’s custom components that are eligible for use in the
context of a navigator container.
6. Set the Label of the new pane as Catalog.
22_488959-ch16.indd 47522_488959-ch16.indd 475 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
476
7. Select Books from the list of available containers.
8. Click OK to add the new pane to the ViewStack.
9. Repeat Steps 5 through 8, and add an instance of the Authors container with a
label of Authors.
FIGURE 16.3
The Insert Pane dialog box
10. Repeat Steps 5 through 8 again, and add an instance of the ShoppingCart
container with a label of Shopping Cart.
11. Click the left arrow button three times to return to the first layer of the
ViewStack. It should be blank.
12. Click the – button to remove the first layer, leaving only the three you added.
13. Run the application. When the application appears, it should display the Books con-
tainer, because it was the first layer declared within the

ViewStack.
Note
The application displays only one layer at this point, because you haven’t added any interactive components to
control navigation.
n
14. Return to Flash Builder, and switch to Source mode.
The generated
ViewStack code looks like this:
22_488959-ch16.indd 47622_488959-ch16.indd 476 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
477
<mx:ViewStack id=”viewstack1” width=”200” height=”200”>
<views:Books label=”Catalog” width=”100%” height=”100%”>
</views:Books>
<views:Authors label=”Authors” width=”100%” height=”100%”>
</views:Authors>
<views:ShoppingCart label=”Shopping Cart” width=”100%”
height=”100%”>
</views:ShoppingCart>
</mx:ViewStack>
The Design mode tool for generating ViewStack code makes a great start but has these issues:
l
The ViewStack is always generated with an initial height and width of 200
pixels each. You can change the
ViewStack dimensions in Design mode by dragging
the
ViewStack handles, or in the Properties view. And of course, you can always change
or remove the dimensions completely in Source mode.
l

Design mode has no mechanism for visually reordering a ViewStack container’s
layers. If you want to change the order of the views, you must do so in Source mode by
changing the order of the child containers.
l
All containers’ MXML declarations are generated with tag sets, such as:
<views:Books label=”Catalog” width=”100%” height=”100%”>
</views:Books>
Particularly when using custom components, the MXML code would be more efficient
with empty tag syntax:
<views:Books label=”Catalog” width=”100%” height=”100%”/>
This is purely a matter of code aesthetics though, and it doesn’t have any negative effect
on application functionality or performance.
After generating a
ViewStack in Design mode, revise the generated code as needed in Source mode.
Working with navigator containers in ActionScript
When a navigator container is initially constructed and displayed, it displays the currently active
view (by default, the first view declared in the stack). You can change the active view at runtime
with ActionScript commands that reference one of these
ViewStack properties:
l
selectedIndex:int. The numeric index position of the active container within the stack.
l
selectedChild:Container. The object reference of the active container within the stack.
Using selectedIndex
The selectedIndex property returns the index position of the currently active container, as
determined by the order of the
ViewStack container’s display list. When declaring a ViewStack
in MXML, the display list order and the order of MXML declaration are the same.
As with all index operations in ActionScript, indexing starts at 0. So the first container with the
view stack is at position 0, the second at position 1, and so on.

22_488959-ch16.indd 47722_488959-ch16.indd 477 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
478
To change the currently selected view by index, set the stack’s selectedIndex property to the
numeric index of the container you want to activate. This code makes the
viewstack1 contain-
er’s second layer visible and active:
<s:Button label=”Authors” click=”viewstack1.selectedIndex=1”/>
Because indexing always begins at 0, this Button would enable the user to navigate to the first
layer of a stack:
<s:Button label=”First Layer” click=”viewstack1.selectedIndex=0”/>
Using numChildren
The numChildren property returns the total number of layers in the stack as an int value.
Taking into account the 0-based indexing offset, clicking this
Button would result in navigating
to the last layer of a stack:
<s:Button label=”Last Layer”
click=”viewstack1.selectedIndex=viewstack1.numChildren-1”/>
Navigating forward and backward through view stack layers
You can navigate forward and backward through layers of a view stack by incrementing or decre-
menting the stack’s
selectedIndex property. This Button would enable the user to move to
the previous layer of a stack:
<s:Button label=”Authors” click=”viewstack1.selectedIndex ”/>
Note
The selectedIndex property of a ViewStack can’t be set to less than 0. If the Button control in the pre-
ceding code is clicked when the
ViewStack container’s selectedIndex is already set to 0, the command is
ignored and there is no runtime error.

n
You also can navigate forward through a stack, but if you set the selectedIndex to a value
greater than the stack’s highest available index, an “array out of bounds” error results. You can pre-
vent this by wrapping the code to navigate forward in a conditional clause that checks to be sure
that the last container in the stack isn’t already active:
private function navForward():void
{
if (viewstack1.selectedIndex != viewstack1.numChildren-1)
{
viewstack1.selectedIndex++;
}
}
Alternatively, you can set the Button control’s enabled property to false when selected
Index
indicates that a forward or backward navigation either wouldn’t work or would result in a
runtime error. Binding expressions that evaluate
selectedIndex and return a Boolean value
to the
enabled property can handle this task dynamically.
22_488959-ch16.indd 47822_488959-ch16.indd 478 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
479
The following Button control that navigates forward is enabled only when the ViewStack con-
tainer’s
selectedIndex isn’t already set to the highest index:
<s:Button label=”Next &gt;&gt;”
click=”viewstack1.selectedIndex++”
enabled=”{viewstack1.selectedIndex != viewstack1.numChildren-1}”/>
Managing binding issues

In the preceding code example, the binding expression used in the enabled property might be
executed upon application startup before the
ViewStack container’s numChidren property can
be correctly evaluated. If this happens, you might see that the
Button controls are incorrectly
enabled and disabled upon application startup.
To fix this sort of timing issue, call the
ViewStack container’s executeBindings() method
with a recursive argument of
true to reevaluate all its dependent binding expressions. If you call
this method upon the
ViewStack container’s creationComplete event, it evaluates any
bound property values such as
numChildren again and the Button control’s enabled states
will be correctly calculated:
<mx:ViewStack id=”viewstack1” width=”400” height=”200”
creationComplete=”executeBindings(true)”>
<views:Books label=”Catalog” width=”100%” height=”100%”/>
<views:Authors label=”Authors” width=”100%” height=”100%”/>
<views:ShoppingCart label=”Shopping Cart” width=”100%”
height=”100%”/>
</mx:ViewStack>
The application in Listing 16.2 implements forward and backward navigation with a ViewStack
and
Button controls. Each Button control has its enabled property set through a binding
expression, and the
ViewStack re-executes its bindings upon its creationComplete event.
LISTING 16.2
An application using forward and backward navigation
<?xml version=”1.0” encoding=”utf-8”?>

<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>
<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header/>
<s:HGroup>
continued
22_488959-ch16.indd 47922_488959-ch16.indd 479 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
480
LISTING 16.2
(continued)
<s:Button label=”&lt;&lt; Previous”
click=”viewstack1.selectedIndex ”
enabled=”{viewstack1.selectedIndex != 0}”/>
<s:Button label=”Next &gt;&gt;”
click=”viewstack1.selectedIndex++”
enabled=”{viewstack1.selectedIndex !=
viewstack1.numChildren-1}”/>
</s:HGroup>
<mx:ViewStack id=”viewstack1” width=”400” height=”200”
creationComplete=”executeBindings(true)”>
<views:Books label=”Catalog” width=”100%” height=”100%”/>
<views:Authors label=”Authors” width=”100%” height=”100%”/>

<views:ShoppingCart label=”Shopping Cart” width=”100%” height=”100%”/>
</mx:ViewStack>
</s:Application>
On the Web
The code in Listing 16.2 is available in the Web site files as BookStoreIndexNavigation.mxml in the
chapter16 project.
n
Figure 16.4 shows the resulting application, with Previous and Next buttons to handle backward
and forward navigation.
Using selectedChild
The ViewStack container’s selectedChild property accesses the stack’s currently visible view
by its object reference. To use this property, each of the stack’s nested containers should be
assigned a unique
id:
<mx:ViewStack id=”viewstack1”>
<views:Books id=”booksView”/>
<views:Authors id=”authorsView”/>
<views:ShoppingCart id=”cartView”/>
</mx:ViewStack>
To select an active view by the container’s unique id, set the ViewStack container’s
selectedChild:
<s:Button label=”Shoppping Cart”
click=”viewstack1.selectedChild=cartView”/>
Note
Notice that there are no quotes around the cartView container’s id when it’s assigned in this way. You’re
accessing the
id as a variable or component instance id, not a String value.
n
22_488959-ch16.indd 48022_488959-ch16.indd 480 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

Chapter 16: Managing Application Navigation
481
FIGURE 16.4
An application with forward and backward navigation
Note
When navigating with selectedChild set to a container’s unique id, because your navigation will be hard-
coded, you typically don’t need to assign a
label property to each container. The label property becomes
useful when dynamically generating user interface controls for navigation.
n
The application in Listing 16.3 implements navigation using Button controls for each of the
nested containers in a
ViewStack. Each Button control explicitly navigates to its container by
the container’s unique
id.
LISTING 16.3
An application using explicit navigation by unique id
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>
continued
22_488959-ch16.indd 48122_488959-ch16.indd 481 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
482
LISTING 16.3
(continued)

<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header/>
<s:HGroup>
<s:Button label=”Catalog”
click=”viewstack1.selectedChild=booksView”/>
<s:Button label=”Authors”
click=”viewstack1.selectedChild=authorsView”/>
<s:Button label=”Shopping Cart”
click=”viewstack1.selectedChild=cartView”/>
</s:HGroup>
<mx:ViewStack id=”viewstack1” width=”400” height=”200”>
<views:Books id=”booksView” width=”100%” height=”100%”/>
<views:Authors id=”authorsView” width=”100%” height=”100%”/>
<views:ShoppingCart id=”cartView” width=”100%” height=”100%”/>
</mx:ViewStack>
</s:Application>
On the Web
The code in Listing 16.3 is available in the Web site files as BookStoreReferenceNavigation.mxml in
the
chapter16 project.
n
Figure 16.5 shows the resulting application, with explicit Button controls to handle navigation to
each nested container.
Managing creation policy
The ViewStack, TabNavigator, and Accordion containers support a property named
creationPolicy that manages the manner in which their nested view containers are instanti-
ated at runtime. These are possible values of

creationPolicy:
l
auto (the default)
l
all
l
none
l
queued
When creationPolicy is set to the default of auto, only the initially active view is completely
instantiated at first. The other view containers also are instantiated, but their child controls are left
null. Any attempt to address these objects in ActionScript code while they’re not yet instantiated
results in a null error.
22_488959-ch16.indd 48222_488959-ch16.indd 482 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
483
FIGURE 16.5
An application with explicit navigation by unique id
This behavior is known as deferred instantiation and is a strategy for optimizing client-side perfor-
mance in Flash Player. In a navigator container that contains dozens of views or more, if the applica-
tion has to instantiate all the content before the user can interact with anything, significant delays
can occur. To prevent this issue, the default behavior makes content visible as early as possible.
You see the effect of deferred instantiation when you try to initialize some property of a nested
component before the user decides to visit that content at runtime and get a runtime error. You
can solve this by setting the navigator container’s
creationPolicy property to all, meaning
that all the views are instantiated during the navigator container’s instantiation. This strategy can
work fine in a small- to medium-size application that doesn’t have a large number of nested views,
or if you need to interact with child objects of nested views prior to the user viewing them.

Alternatively, you can set
creationPolicy to none, meaning that you don’t want the nested
components ever to be instantiated automatically, and then take complete control over the process
by explicitly calling the nested container’s
createComponentsFromDescriptors() method
when you see fit.
Note
The Container class implements such methods as addChild(), addChildAt(), and removeChild()
that enable you to explicitly control the contents and order of a container’s nested child objects at runtime.
You can use these methods to control not just which objects have been instantiated, but which are currently
nested children of a navigator container.
n
22_488959-ch16.indd 48322_488959-ch16.indd 483 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
484
Tip
The creationPolicy property is also implemented in layout containers. Layout containers instantiate all
their child objects at the same time by default. If you prefer to take control over the instantiation process, set
the layout container’s
creationPolicy property to none, and then instantiate the child objects as neces-
sary using with the container’s
createComponentsFromDescriptors() method.
n
Finally, the effect of setting creationPolicy to queued means that you want to instantiate all
objects automatically, but instead of creating all objects simultaneously (as with the setting of
all), each nested view component’s content is instantiated only after the prior component’s
instantiation has been completed.
Managing navigator container dimensions
By default, navigator containers size to the first visible child container. Any subsequent navigation

results in bumping the child container up to the top left if it is smaller than the instantiated size, or
the implementation of scrollbars if the container is larger.
You can set the height and width of a navigator container using absolute pixel dimensions, per-
centage dimensions, or dynamic sizing. You can use two common strategies for handling navigator
container sizing:
l
Set the navigator container’s dimensions to specific pixel or percentage dimensions,
and then set the nested container sizes to 100 percent height and width. Each of the
nested view containers then resizes to fill the available space in the navigator container.
l
Set the nested containers to specific pixel dimensions, and set the navigator contain-
er’s resizeToContent property to true. The navigator container then resizes to accom-
modate each newly active view as the user navigates through the application.
Caution
Setting resizeToContent to true forces the navigator container to remeasure and redraw itself as the user
navigates through the application. This can cause interesting and unintended visual effects, particularly when
the navigator container has a visible border or background.
n
Using Navigator Bar Containers
If you want a user to be able to navigate to any container within a ViewStack, you can use one of
the navigator bar containers that are included with the Flex framework. The framework uses four
navigator bar containers:
l
ButtonBar. Generates one Button control for each nested container. There are both
MX and Spark versions of
ButtonBar. The Spark version implements toggle buttons,
making the
ToggleButtonBar component unnecessary.
l
LinkBar. Generates one MX LinkButton control for each nested container.

22_488959-ch16.indd 48422_488959-ch16.indd 484 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
485
l
TabBar. Generates one Tab for each nested container.
l
ToggleButtonBar. Generates one MX Button control for each nested container and
shows the current selection through the
Button control’s toggle behavior.
Note
You won’t find a Tab component or ActionScript class in the Flex documentation, but it’s used internally as a
style selector to manage a
TabBar’s visual presentation. Because each Tab is an instance of this internal class,
you can change certain styles such as the amount of padding within each
Tab:
<fx:Style>
@namespace mx “library://ns.adobe.com/flex/mx”;
mx|Tab {
padding-left:10;
padding-bottom:0;
padding-top:0;
padding-right:10;
}
</fx:Style>
n
Using a data collection as a dataProvider
Each of the navigator bar containers has a dataProvider property that you can set either to a
collection of data or to a
ViewStack by referencing its id. The MX navigator bar containers can

accept an
Array or ArrayCollection, while the Spark ButtonBar can accept an
ArrayList or ArrayCollection, but not an Array.
When using a data collection as the navigator bar’s
dataProvider, the navigator bar generates
one interactive component for each of the
dataProvider object’s data items.
The application in Listing 16.4 generates a Spark
ButtonBar using a dataProvider set from
an
ArrayList of complex objects. Because the Array contains three data items, the user sees
three
Button objects.
LISTING 16.4
A LinkBar with items generated from an ArrayCollection
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”>
<fx:Script>
<![CDATA[
import spark.events.IndexChangeEvent;
protected function buttonbar_changeHandler(
event:IndexChangeEvent):void
continued
22_488959-ch16.indd 48522_488959-ch16.indd 485 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
486
LISTING 16.4

(continued)
{
var buttonURL:String = buttonData.getItemAt(event.newIndex).url;
var request:URLRequest = new URLRequest(buttonURL);
navigateToURL(request);
}
]]>
</fx:Script>
<fx:Declarations>
<s:ArrayList id=”buttonData”>
<fx:Object>
<fx:label>Adobe</fx:label>
<fx:url></fx:url>
</fx:Object>
<fx:Object>
<fx:label>Google</fx:label>
<fx:url></fx:url>
</fx:Object>
<fx:Object>
<fx:label>Microsoft</fx:label>
<fx:url></fx:url>
</fx:Object>
</s:ArrayList>
</fx:Declarations>
<s:ButtonBar change=”buttonbar_changeHandler(event)”
dataProvider=”{buttonData}”
horizontalCenter=”0” top=”20”/>
</s:Application>
On the Web
The code in Listing 16.4 is available in the Web site files as NavBarWithArrayData.mxml in the

chapter16 project.
n
Note
In the preceding code, the <fx:Object> tags are declared separately and then bound to the ButtonBar
object’s
dataProvider.
n
Note
The label and url property names are arbitrary and not predefined in the Object class, but the fx prefix is
required because they’re declared within the
<fx:Object> tag set. The value of the label property is used
in the labels of the navigator bar container’s generated controls because the container’s
labelField prop-
erty defaults to
label. You can use any other named object property for this purpose by setting the
labelField to the property you want to use.
n
22_488959-ch16.indd 48622_488959-ch16.indd 486 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
487
Handling navigator bar events
When a navigator bar’s dataProvider is set as a data collection, it doesn’t automatically do any-
thing when the user clicks one of its controls. Instead, you handle the navigator bar’s
itemClick
event for MX controls, and the change event for the Spark
ButtonBar, by executing some
ActionScript code.
The
itemClick event generates an event object typed as mx.events.ItemClickEvent. This

object has an
item property that references the underlying data of the interactive component that
was clicked. Within an event handler function, the expression
event.item returns the underly-
ing data, and from that point you can reference the selected object’s data properties.
The change event generates an event object typed as
spark.events.IndexChangeEvent. The
object has properties named
newIndex and oldIndex that tell you which object has been
selected by the user (based on its index position in the data collection) and which object was
selected before the event.
The application in Listing 16.4 handles the
change event of a Spark ButtonBar control and
responds by navigating to the selected URL.
Using a ViewStack as a dataProvider
When you pass a ViewStack to a navigator bar as its dataProvider, the navigator bar gener-
ates one interactive control for each of the
ViewStack container’s nested views. Each nested con-
tainer’s
label property is passed to each generated Button, LinkButton, or Tab for display. It
also automatically causes its bound
ViewStack to navigate to the related view when a control in
the bar is clicked.
You set a
ViewStack as a dataProvider with a binding expression:
<s:ButtonBar dataProvider=”{viewstack1}”/>
The application in Listing 16.5 uses a ToggleButtonBar that generates one toggle button for
each nested container of a
ViewStack.
LISTING 16.5

An application using a navigator bar container
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>
<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
continued
22_488959-ch16.indd 48722_488959-ch16.indd 487 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
488
LISTING 16.5
(continued)
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header/>
<s:ButtonBar dataProvider=”{viewstack1}”/>
<mx:ViewStack id=”viewstack1” width=”400” height=”200”>
<views:Books label=”Catalog” width=”100%” height=”100%”/>
<views:Authors label=”Authors” width=”100%” height=”100%”/>
<views:ShoppingCart label=”Shopping Cart” width=”100%” height=”100%”/>
</mx:ViewStack>
</s:Application>
On the Web
The code in Listing 16.5 is available in the Web site files as BookStoreNavBar.mxml in the chapter16
project.
n

Figure 16.6 shows the resulting application, with generated toggle button controls to handle navi-
gation to each nested container.
Note
The Spark ButtonBar component’s primary advantage over the MX navigation toolbars is that it supports cus-
tom skins using the new Spark skinning architecture. It also differs from the MX
ButtonBar in that it toggles
buttons automatically as navigation occurs, staying in sync with its bound ViewStack. In this behavior it’s clos-
est in functionality to the MX
ToggleButtonBar.
n
Managing navigator bar presentation
Each of the MX navigator bar containers has a direction property that can be used to lay out
the container vertically. For example, this
LinkBar stacks its generated LinkButton controls
vertically:
<mx:LinkBar dataProvider=”{viewstack1}” direction=”vertical”/>
The application in Listing 16.6 uses a vertical LinkBar wrapped in an HBox container. Binding
expressions are used to match the component’s width and height properties as needed.
LISTING 16.6
An application using a vertical navigator bar container
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
22_488959-ch16.indd 48822_488959-ch16.indd 488 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
489
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>

<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header id=”header”/>
<s:HGroup width=”{header.width}”>
<mx:LinkBar dataProvider=”{viewstack1}”
direction=”vertical”
backgroundColor=”white” backgroundAlpha=”.8”
height=”{viewstack1.height}”/>
<mx:ViewStack id=”viewstack1” width=”100%” height=”200”>
<views:Books label=”Catalog” width=”100%” height=”100%”/>
<views:Authors label=”Authors” width=”100%” height=”100%”/>
<views:ShoppingCart label=”Shopping Cart” width=”100%” height=”100%”/>
</mx:ViewStack>
</s:HGroup>
</s:Application>
FIGURE 16.6
An application using a navigator bar container
22_488959-ch16.indd 48922_488959-ch16.indd 489 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
490
On the Web
The code in Listing 16.6 is available in the Web site files as BookStoreVerticalNav.mxml in the
chapter16 project.
n
Figure 16.7 shows the resulting application, with a vertical LinkBar displaying stacked
LinkButton controls.
FIGURE 16.7

An application using a vertical navigator bar container
The Spark ButtonBar component’s direction property takes values of ltr and rtl, which
controls the order of button creation (left-to-right or right-to-left). Its
layout property is like the
same property as implemented in the Spark
Application, Panel and List components: it
accepts an instance of one of the layout classes such as
VerticalLayout, HorizontalLayout,
or
TileLayout.
The application in Listing 16.7 displays a Spark
ButtonBar with its buttons stacked vertically.
LISTING 16.7
An application using a vertical Spark ButtonBar component
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
22_488959-ch16.indd 49022_488959-ch16.indd 490 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
491
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”
xmlns:views=”views.*”>
<s:layout>
<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Style source=”assets/styles.css”/>
<views:Header id=”header”/>
<s:HGroup width=”{header.width}”>

<s:ButtonBar dataProvider=”{viewstack1}”
height=”{viewstack1.height}”>
<s:layout>
<s:VerticalLayout/>
</s:layout>
</s:ButtonBar>
<mx:ViewStack id=”viewstack1” width=”100%” height=”200”>
<views:Books label=”Catalog” width=”100%” height=”100%”/>
<views:Authors label=”Authors” width=”100%” height=”100%”/>
<views:ShoppingCart label=”Shopping Cart” width=”100%” height=”100%”/>
</mx:ViewStack>
</s:HGroup>
</s:Application>
On the Web
The code in Listing 16.7 is available in the Web site files as BookStoreVerticalButtonBar.mxml in the
chapter16 project.
n
Note
The Spark ButtonBar is a skinnable component. Its default skin declares each button object as an instance of
spark.components.ButtonBarButton, which extends the Spark ToggleButton component. You can
change the appearance of the
ButtonBar component and its child button objects by creating custom skins
both for the navigator container and for its children.
n
Using Menu Controls
Flex provides three menu controls that you can use to create styles of navigation interfaces. They
include the MX
Menu, MenuBar, and PopupMenuButton controls. Of these three controls, the
Menu and MenuBar define their menus with a hierarchical data structure, represented as XML,
and notify you of user selections with both an

itemClick and change event.
The
PopupMenuButton control differs from the other menu controls, in that it displays only a
single-level menu and notifies you of a user selection with its
change event. In this section I
describe the details of using the
Menu and MenuBar controls. The PopupMenuButton control is
described in Chapter 17.
22_488959-ch16.indd 49122_488959-ch16.indd 491 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
492
You can use the Menu and MenuBar controls, combined with event listeners and ActionScript
event handler functions, to create a customized navigation interface.
Menu data providers
The data that determines the structure of a Menu or MenuBar is typically represented hierarchi-
cally and can be one of these types:
l
A String containing valid XML text
l
An XMLNode
l
An XMLList
l
Any object that implements ICollectionView
l
An Array
Any other object passed as a menu data provider is automatically wrapped in an Array with the
object as its first and only item.
The most common sort of data used to determine menu structure is an

XMLList. You can declare
an
XMLList in the application with MXML code and nested XML markup:
<fx:Declarations>
<mx:XMLList id=”menuData”>
<menuitem label=”Lists”>
<menuitem label=”Catalog” view=”catalogView”/>
<menuitem label=”Authors” view=”authorsView”/>
</menuitem>
<menuitem label=”Shopping”>
<menuitem label=”Shopping Cart” view=”cartView”/>
</menuitem>
</mx:XMLList>
</fx:Declarations>
Tip
As with all nonvisual objects, instances of XML and XMLList must be declared inside an
<fx:Declarations> element in Flex 4 applications.
n
You can select any element and attribute names you like in the XML structure, but you should
follow these recommendations when using a menu control with a
ViewStack:
l
Each menu item should have a consistently named attribute to serve as the visible
label for each menu node. In the preceding example, this attribute is named
label.
Notice that all menu items at all levels of the hierarchy have this attribute.
l
Menu items that cause navigation should have an attribute whose value matches the
unique
id of a nested container in a ViewStack. This can help you simplify the

ActionScript code you write to handle the menu control’s events.
22_488959-ch16.indd 49222_488959-ch16.indd 492 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
493
To use the data in a menu control, pass the XMLList structure to the control as its dataProvider
property in a binding expression. Also set the menu control’s
labelField to an E4X (ECMAScript
for XML) expression that references the
label attribute in each menu node:
<mx:MenuBar id=”myMenuBar” dataProvider=”{menuData}”
labelField=”@label”/>
Cross-Reference
Detailed information about retrieving XML and parsing it with E4X is available in Chapters 23 and 24.
n

Caution
If you forget to set the menu control’s labelField to a consistently named attribute or property of the
underlying data, the labels of the menu items sometimes present raw XML because the control doesn’t have
any instructions for parsing the data.
n
Handling menu events
When the user selects an item from either the Menu or MenuBar control, it dispatches an item
Click
event that generates an event object typed as mx.events.MenuEvent. This event object
has an
item property that references the underlying data that drove the creation of the selected
menu item. Within an event handler function, the expression
event.item references the data,
and the E4X expression can be used to access the selected XML node’s attributes. For example, the

expression
event.item.@view references the XML node’s view attribute.
You can listen for the
itemClick event with MXML or ActionScript. This MenuBar has an
attribute-based
itemClick event listener that passes the event object to a custom event handler
function named
menu_ClickHandler():
<mx:MenuBar id=”myMenuBar” dataProvider=”{menuData}”
labelField=”@label” itemClick=”menu_ClickHandler(event)”/>
To listen for the same event with an ActionScript statement, use the addEventListener()
method to listen for the event named by the constant
MenuEvent.ITEM_CLICK:
navMenu.addEventListener(MenuEvent.ITEM_CLICK, menu_ClickHandler);
The custom event handler can then access the selected XML node’s attributes and use them to exe-
cute navigation. This event handler function retrieves the node’s
view attribute with an array-style
expression to change the active view container of the
ViewStack:
import mx.events.MenuEvent;
private function menu_ClickHandler(event:MenuEvent):void
{
viewstack1.selectedChild = this[event.item.@view];
}
22_488959-ch16.indd 49322_488959-ch16.indd 493 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Part II: Designing Flex Applications
494
Using the Menu control
The Menu control presents a set of cascading menus in response to a user event. Because this con-

trol is always presented in response to an event, and not as a static part of the application’s visual
interface, it can be instantiated only with ActionScript, not with MXML.
To create a
Menu, instantiate it with the Menu class’s static createMenu() method and pass two
arguments:
l
The Menu object’s parent container
l
The Menu object’s data provider
Then present the
Menu with its show() method, passing optional xShow and yShow coordinates
as arguments. This event handler function responds to a mouse event by creating a
Menu with a
data provider named
menuData and the application as the parent window, and then displays it at
the mouse event’s
stageX and stageY coordinates.
The application in Listing 16.8 uses a
Menu populated with an XMLList as its dataProvider.
LISTING 16.8
Using the Menu control
<?xml version=”1.0” encoding=”utf-8”?>
<s:Application xmlns:fx=”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx”>
<s:layout>
<s:VerticalLayout horizontalAlign=”left”
paddingTop=”20” paddingLeft=”20”/>
</s:layout>
<fx:Script>

<![CDATA[
import mx.events.MenuEvent;
import mx.controls.Alert;
import mx.controls.Menu;
private function showMenu(event:MouseEvent):void
{
var navMenu:Menu = Menu.createMenu(this, menuData);
navMenu.labelField=”@label”;
navMenu.addEventListener(MenuEvent.ITEM_CLICK, menuClickHandler);
navMenu.show(event.stageX,event.stageY);
}
private function menuClickHandler(event:MenuEvent):void
{
Alert.show(“You selected “ + event.item.@label, “Menu Selection”);
}
]]>
</fx:Script>
22_488959-ch16.indd 49422_488959-ch16.indd 494 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Chapter 16: Managing Application Navigation
495
<fx:Declarations>
<fx:XMLList id=”menuData”>
<menuitem label=”Lists”>
<menuitem label=”Catalog” view=”catalogView”/>
<menuitem label=”Authors” view=”authorsView”/>
</menuitem>
<menuitem label=”Shopping”>
<menuitem label=”Shopping Cart” view=”cartView”/>
</menuitem>

</fx:XMLList>
</fx:Declarations>
<s:Button label=”Click for Menu” click=”showMenu(event)”/>
</s:Application>
On the Web
The code in Listing 16.8 is available in the Web site files as MenuDemo.mxml in the chapter16 project.
n
Figure 16.8 shows the resulting application. The Menu pops up when the mouse button is released
while over the
Label control.
FIGURE 16.8
Using the Menu control
Using the MenuBar control
The MenuBar control presents a horizontal list of menu items with cascading pull-down sub-
menus. It uses the same sort of data and generates the same events as the
Menu control. Unlike the
Menu, it’s designed to be placed in a static position in the application and serve as a navigation or
functional menu, so it’s typically declared in MXML:
<mx:MenuBar id=”myMenuBar” dataProvider=”{menuData}”
labelField=”@label” itemClick=”menuClickHandler(event)”/>
22_488959-ch16.indd 49522_488959-ch16.indd 495 3/5/10 2:30 PM3/5/10 2:30 PM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

×