This is Part 5 of a multipart series of articles that cover tips and tricks for Flex mobile development. Earlier parts focused on:
- Handling data when switching between views and between application executions
- Styling the ActionBar and tab components in your mobile app
- Controlling the visibility of the ActionBar and tab components, and moving the tab components to the top of your app
- Creating popup alerts
This article covers transitions when switching between views and when switching between tabs.
While navigating through a Flex mobile application from view to view, by default one view slides off the screen as the new one slides on. You can change the animation or effect used in this view transition using one of four different classes that are available in the spark.transitions package in Flex 4.5:
- SlideViewTransition
- CrossFadeViewTransition
- FlipViewTransition
- ZoomViewTransition
Each of these transition classes can be applied with their default properties, or you can set the direction, duration, and mode (for some) to create a different effect. The following code snippets illustrate how each of these classes can be applied:
var
flipTrans:FlipViewTransition = new FlipViewTransition(); flipTrans.direction =
ViewTransitionDirection.UP; flipTrans.mode = FlipViewTransitionMode.CUBE; //or
CARD mode navigator.pushView(SampleZoom,null,null,flipTrans); var
zoomTrans:ZoomViewTransition = new ZoomViewTransition(); zoomTrans.direction =
ViewTransitionDirection.RIGHT; zoomTrans.mode = ZoomViewTransitionMode.IN; //or
OUT mode navigator.popToFirstView(zoomTrans); var slideTrans:SlideViewTransition
= new SlideViewTransition(); slideTrans.direction =
ViewTransitionDirection.DOWN; slideTrans.mode = SlideViewTransitionMode.UNCOVER;
//or COVER and PUSH modes navigator.pushView(SampleZoom,null,null,slideTrans);
var fadeTrans:CrossFadeViewTransition = new CrossFadeViewTransition();
fadeTrans.direction = ViewTransitionDirection.LEFT; // no modes are available
for CrossFadeViewTransition navigator.pushView(SampleZoom,null,null,fadeTrans);
By default SlideViewTransition (with PUSH
mode
and LEFT
direction) is used for the pushing and popping
of all views. You can change the default transition used when a new view is
pushed onto the stack by
settingnavigator.defaultPushTransition
. Likewise, you can
setnavigator.defaultPopTransition
to change the default
transition used when the view is popped off the view stack (so the view beneath
it is shown) .
In either case, you set the property to an
instance of a transition class; for example:
navigator.defaultPushTransition
= new FlipViewTransition(); navigator.defaultPopTransition = new
FadeViewTransition();
You can set these properties on any navigator within the main ViewNavigatorApplication or TabbedViewNavigatorApplication. You can also set them on the View class itself. However, if you want the change to apply to the entire application, set it in the root application code.
To see how this works, download the sample files for this article and
import ViewTransitionsSample.fxp into Flash Builder. The
application (see Figure 1) demonstrates the transitions and shows how to use the
different modes that are available. For example, with FlipViewTransition you can
see the difference
betweenCARD
and CUBE
mode. You can also
test how applying an easing function such
as Bounce
or Elastic
might affect how it
plays. Fun stuff!
Below is a short video clip of the application running on an iPod Touch. It‘s nothing fancy, but you can see the different effects played when the four different view transition types are used.
All of the ViewTransition classes extend ViewTransitionBase. The ViewTransitionBase class (and all
that extend it) will
dispatch FlexEvent.TRANSITION_START
and FlexEvent.TRANSITION_END
events
when the transition starts and ends respectively. You can create your own custom
transitions by extending ViewTransitionBase. If you plan to do so though, you
should first review the Flex 4.5 ViewTransition specification. Note that this is the
original specification and some names of properties, events, and other details
have changed.
The ViewTransition classes are great for applying an effect to your view navigation within a ViewNavigator. However, you cannot use the ViewTransition classes when switching between tabs, because you are no longer operating within the same ViewNavigator, but rather between ViewNavigator containers. It is, however, still possible to apply similar effects to those provided by ViewTransition, and I‘ve outlined one approach below.
First, you need to add an IndexChangeEvent handler to the
implicit tabbedNavigator
property in your
TabbedViewNavigatorApplication on applicationComplete
;
for example:
protected
function
tabbedviewnavigatorapplication1_applicationCompleteHandler(event:FlexEvent):void
{ this.tabbedNavigator.addEventListener(IndexChangeEvent.CHANGE,onChange); }
The IndexChangeEvent.CHANGE
event is dispatched when a
tab is selected, so you can perform any necessary handling within the handler.
In this case, you want to apply a Spark Effect to the View that is being
selected. You can check the newIndex
property on
the IndexChangeEvent
and play different effects for each
tab if you want.
You‘ll need to set up some effects to use. For example, you can define the following in the root application MXML:
<fx:Declarations>
<s:Sequence id="seqEffect"> <s:Parallel> <s:Scale duration="800"
id="scaleUp" scaleXBy=".8"/> <s:Rotate3D angleYFrom="0.0" angleYTo="360"
duration="1600" repeatCount="{2}" repeatBehavior="reverse"/>
</s:Parallel> <s:Scale duration="300" id="scaleDown"
scaleXBy="-.8"/> </s:Sequence> <s:Move3D id="moveEffect"
duration="300" xFrom="400" xTo="0"/> <s:Fade duration="800"
id="fadeEffect" alphaFrom="0" alphaTo="1.0"/> </fx:Declarations>
Note: If you‘re not familiar with Spark Effects, check out Tour de Flex under Flex 4 > Components > Effects to see examples of how to use them all.
In the onChange
handler, simply check the event index
and set the target of the effect to the matching ViewNavigator
container‘s activeView
property:
protected
function onChange(event:IndexChangeEvent):void { if (event.newIndex == 0)
seqEffect.play([v1.activeView]); else if (event.newIndex == 1)
moveEffect.play([v2.activeView]); else if (event.newIndex == 2)
fadeEffect.play([v3.activeView]); }
Since you‘re handling
the IndexChangeEvent.CHANGE
event and not
theIndexChangeEvent.CHANGING
event, you can be sure
that activeView
has been set to the ViewNavigator
container‘s new active view.
When the effects are played you will see a transition of sorts similar to what you might see when using a ViewTransition. You can see that you could also create more complex transitions using a sequence or parallel set of effects, and even add an easing function if desired. To simply mimic the ViewTransition classes, you would likely use the Spark Fade, Move, Rotate3D, and Scale effects alone to replicate the CrossFadeViewTransition, SlideViewTransition, FlipViewTransition, and ZoomViewTransition classes respectively. The code above will cause the effect to apply to the View itself, similar to how the ViewTransition classes work by default. However, you could also have the effect include the action bar in the animation as well by changing the code as follows:
protected
function onChange(event:IndexChangeEvent):void { if (event.newIndex == 0)
seqEffect.play([v1]); else if (event.newIndex == 1) moveEffect.play([v2]); else
if (event.newIndex == 2) fadeEffect.play([v3]); }
Here is the full source for the main TabbedViewNavigatorApplication class:
<?xml
version="1.0" encoding="utf-8"?> <s:TabbedViewNavigatorApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
applicationComplete="tabbedviewnavigatorapplication1_applicationCompleteHandler(event)">
<fx:Style source="styles.css"/> <fx:Script> <![CDATA[ import
mx.events.FlexEvent; import spark.events.IndexChangeEvent; import
views.SlideView; protected function
tabbedviewnavigatorapplication1_applicationCompleteHandler(event:FlexEvent):void
{ this.tabbedNavigator.addEventListener(IndexChangeEvent.CHANGE,onChange); }
protected function onChange(event:IndexChangeEvent):void { if (event.newIndex ==
0) seqEffect.play([v1.activeView]); else if (event.newIndex == 1)
moveEffect.play([v2.activeView]); else if (event.newIndex == 2)
fadeEffect.play([v3.activeView]); } ]]> </fx:Script>
<fx:Declarations> <s:Sequence id="seqEffect"> <s:Parallel>
<s:Scale duration="800" id="scaleUp" scaleXBy=".8"/> <s:Rotate3D
angleYFrom="0.0" angleYTo="360" duration="1600" repeatCount="{2}"
repeatBehavior="reverse"/> </s:Parallel> <s:Scale duration="300"
id="scaleDown" scaleXBy="-.8"/> </s:Sequence> <s:Move3D
id="moveEffect" duration="300" xFrom="400" xTo="0"/> <s:Fade
duration="800" id="fadeEffect" alphaFrom="0" alphaTo="1.0"/>
</fx:Declarations> <s:ViewNavigator id="v1" label="Welcome"
width="100%" height="100%" firstView="views.WelcomeView"
activate="seqEffect.play([v1.activeView])"/> <s:ViewNavigator id="v2"
label="Slide View" width="100%" height="100%" firstView="views.SlideView" />
<s:ViewNavigator id="v3" label="Fade View" width="100%" height="100%"
firstView="views.FadeInView" /> </s:TabbedViewNavigatorApplication>
If you want to play an initial effect when the application is run on the
first view, you can also add anactivate
event handler on the
ViewNavigator and play the effect on the active view in the same manner, such
as:
<s:ViewNavigator id="v1" label="Welcome" width="100%" height="100%"
firstView="views.WelcomeView"
activate="effect1.play([v1.activeView])"/>
Here‘s a short, 28-second video of this running on my iPhone 4:
The full source code for the sample application (see Figure 2) is available with the sample files for this article.