You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ti...@apache.org on 2012/01/13 00:15:19 UTC

svn commit: r1230830 [4/4] - in /incubator/flex/whiteboard/tink/iview: ./ examples/ examples/libs/ examples/src/ src/ src/org/ src/org/apache/ src/org/apache/spark/ src/org/apache/spark/components/ src/org/apache/spark/components/supportClasses/ src/or...

Added: incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/SlideViewTransition.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/SlideViewTransition.as?rev=1230830&view=auto
==============================================================================
--- incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/SlideViewTransition.as (added)
+++ incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/SlideViewTransition.as Thu Jan 12 23:15:17 2012
@@ -0,0 +1,872 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2010 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.spark.transitions
+{
+	
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	import mx.core.IVisualElement;
+	import mx.core.mx_internal;
+	import mx.effects.IEffect;
+	
+	import spark.components.ActionBar;
+	import spark.components.Group;
+	import spark.components.SkinnableContainer;
+	import spark.components.TabbedViewNavigator;
+	import spark.components.ViewNavigator;
+	import spark.components.supportClasses.ButtonBarBase;
+	import spark.components.supportClasses.ViewNavigatorBase;
+	import spark.effects.Animate;
+	import spark.effects.Move;
+	import spark.effects.animation.MotionPath;
+	import spark.effects.animation.SimpleMotionPath;
+	import spark.primitives.BitmapImage;
+	import spark.transitions.SlideViewTransitionMode;
+	import spark.transitions.ViewTransitionDirection;
+	import org.apache.spark.components.IView;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  The SlideViewTransition class performs a simple slide transition for views.
+	 *  The existing view slides out as the new view slides in.
+	 *  The slide transition supports several modes (push, cover, and
+	 *  uncover) as well as an optional direction (up, down, left, or right).
+	 *
+	 *  <p><strong>Note:</strong>Create and configure view transitions in ActionScript;
+	 *  you cannot create them in MXML.</p>
+	 *
+	 *  @see SlideViewTransitionMode
+	 *  @see ViewTransitionDirection
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 2.5
+	 *  @productversion Flex 4.5
+	 */
+	public class SlideViewTransition extends ViewTransitionBase
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function SlideViewTransition()
+		{
+			super();
+			
+			// Defaut duration of 300 yields a smooth result.
+			duration = 300;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Flag used to indicate whether the tab bar should animate in or out.
+		 */ 
+		private var animateTabBar:Boolean = false;
+		
+		/**
+		 *  @private
+		 *  Bitmap image of the action bar before it is updated with the properties
+		 *  of the new view.  This snapshot is leveraged by this transition when
+		 *  doing a full screen animation.
+		 */
+		private var cachedActionBar:BitmapImage;
+		
+		/**
+		 *  @private
+		 *  Stores the location of the action bar in the global coordinate space
+		 *  so that the transition can properly position the cached actionbar
+		 *  when added to the display list.
+		 */ 
+		private var cachedActionBarGlobalPosition:Point = new Point();
+		
+		/**
+		 *  @private
+		 *  Variable used to store the startView's initial global position to
+		 *  determine how much it needs to be shifted before a consolidated
+		 *  transition runs.
+		 */ 
+		private var cachedStartViewGlobalPosition:Point;
+		
+		/**
+		 *  @private
+		 *  Bitmap image of the tab bar before it is updated with the properties
+		 *  of the new view.  This snapshot is leveraged by this transition when
+		 *  doing a full screen animation.
+		 */
+		private var cachedTabBar:BitmapImage;
+		
+		/**
+		 *  @private 
+		 *  Stores the location of the action bar in the global coordinate space
+		 *  so that the transition can properly position the cached actionbar
+		 *  when added to the display list.
+		 */
+		private var cachedTabBarGlobalPosition:Point = new Point();
+		
+		/**
+		 *  @private
+		 *  Property bag used to save any start view properties that 
+		 *  are then restored after the transition is complete.
+		 */
+		private var startViewProps:Object;
+		
+		/**
+		 *  @private
+		 *  Property bag used to save any end view properties that 
+		 *  are then restored after the transition is complete.
+		 */
+		private var endViewProps:Object;
+		
+		/**
+		 *  @private
+		 *  Property bag used to save any navigator centric properties that 
+		 *  are then restored after the transition is complete.
+		 */
+		private var navigatorProps:Object;
+		
+		/**
+		 *  @private
+		 */
+		private var transitionGroup:Group;
+		
+		/**
+		 *  @private
+		 *  Indicates whether the end view needs explicit validations during the 
+		 *  transition, which will be the case when the view is in advanced 
+		 *  layout mode.
+		 */ 
+		private var endViewNeedsValidations:Boolean;
+		
+		/**
+		 *  @private
+		 *  Indicates whether the start view needs explicit validations during the 
+		 *  transition, which will be the case when the view is in advanced 
+		 *  layout mode.
+		 */ 
+		private var startViewNeedsValidations:Boolean;
+		
+		/**
+		 *  @private
+		 */ 
+		private var moveEffect:Move;
+		
+		/**
+		 *  @private
+		 */ 
+		private var consolidatedEffect:Animate;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//---------------------------------
+		// direction
+		//---------------------------------
+		
+		private var _direction:String = ViewTransitionDirection.LEFT;
+		
+		[Inspectable(category="General", enumeration="left,right,up,down", defaultValue="left")]
+		/**
+		 *  Specifies the direction of slide transition.
+		 *
+		 *  @default ViewTransitionDirection.LEFT
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get direction():String
+		{
+			return _direction;
+		}
+		
+		/**
+		 *  @private
+		 */ 
+		public function set direction(value:String):void
+		{
+			_direction = value;
+		}
+		
+		//---------------------------------
+		// mode
+		//---------------------------------
+		
+		private var _mode:String = SlideViewTransitionMode.PUSH;
+		
+		[Inspectable(category="General", enumeration="push,cover,uncover", defaultValue="push")]
+		/**
+		 *  Specifies the type of slide transition to perform.
+		 *
+		 *  @default SlideViewTransitionMode.PUSH
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get mode():String
+		{
+			return _mode;
+		}
+		
+		/**
+		 *  @private
+		 */ 
+		public function set mode(value:String):void
+		{
+			_mode = value;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		override mx_internal function preInit():void
+		{
+			if (mode == SlideViewTransitionMode.UNCOVER)
+				setComponentChildIndex(endView, navigator, 0);
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override public function captureStartValues():void
+		{
+			var p:Point;
+			
+			super.captureStartValues();
+			
+			// Initialize the property bag used to save some of our
+			// properties that are then restored after the transition is over.
+			navigatorProps = new Object(); 
+			navigatorProps.initialHeight = navigator.height;
+			
+			// Determine if we will be animating the tabBar as part of the
+			// transition
+			animateTabBar = false;
+			
+			if (tabBar && startView)
+			{
+				// Animate the tabBar if its overlayControls or visible property is toggled.
+				animateTabBar = IView(startView).overlayControls != IView(endView).overlayControls ||
+					IView(startView).tabBarVisible != IView(endView).tabBarVisible;
+			}
+			
+			// Generate initial bitmaps for the transition.  If the transition will be
+			// a push type, we only need to cache the actionBar as we will animate the
+			// views in manually.  If its cover or uncover, an entire image of the navigator
+			// is needed.
+			if (mode != SlideViewTransitionMode.PUSH)
+			{
+				var oldVisibility:Boolean = endView.visible;
+				endView.setVisible( false );
+				
+				if (tabBar && !animateTabBar)
+					cachedNavigator = getSnapshot(targetNavigator.contentGroup, 0, cachedNavigatorGlobalPosition);
+				else                
+					cachedNavigator = getSnapshot(targetNavigator, 0, cachedNavigatorGlobalPosition);
+				
+				endView.setVisible( oldVisibility );
+			}
+			else
+			{
+				cachedActionBar = getSnapshot(navigator.actionBar, 4, cachedActionBarGlobalPosition);
+			}
+			
+			// If the tabBar exists, a bitmap image of it is created
+			if (tabBar)
+			{
+				cachedTabBar = getSnapshot(TabbedViewNavigator(parentNavigator).tabBar, 4, cachedTabBarGlobalPosition);
+				navigatorProps.tabBarIncludeInLayout = tabBar.includeInLayout;
+				navigatorProps.tabBarCacheAsBitmap = tabBar.cacheAsBitmap;
+			}
+			
+			if (startView)
+			{
+				startViewProps = {  includeInLayout: startView.includeInLayout,
+					visible: startView.visible,
+					cacheAsBitmap: startView.cacheAsBitmap,
+					opaqueBackground: startView.opaqueBackground };
+				
+				// Remove the startView from layout so that it doesn't resize as the 
+				// contentGroups of each navigator is resized
+				startView.includeInLayout = false;
+				cachedStartViewGlobalPosition = getTargetNavigatorCoordinates(startView);
+			}
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override protected function createViewEffect():IEffect
+		{   
+			// Prepare our start and end views by positioning them prior to 
+			// the start of our transition, ensuring that they are cached as 
+			// surfaces, and adjust z-order if necessary.
+			
+			var slideTargets:Array = new Array();
+			
+			endViewNeedsValidations = false;
+			startViewNeedsValidations = false;
+			
+			if (startView)
+			{
+				// Store the original x and y position of the view so that we can restore
+				// it after the animation
+				startViewProps.x = startView.x,
+					startViewProps.y = startView.y;
+				
+				startView.cacheAsBitmap = true;
+				
+				// If the startView has an opaque background color, set that as the 
+				// opaqueBackground property to improve performance.
+				if (startView.getStyle("backgroundAlpha") >= 1)
+					startView.opaqueBackground = startView.getStyle("backgroundColor");
+				
+				if( startView is SkinnableContainer )
+				{
+					if (SkinnableContainer(startView).contentGroup)
+					{
+						startViewProps.cgIncludeInLayout = SkinnableContainer(startView).contentGroup.includeInLayout;
+						SkinnableContainer(startView).contentGroup.includeInLayout = false;
+					}
+				}
+				
+				if (mode != SlideViewTransitionMode.COVER)
+				{
+					if (startView.transformRequiresValidations())
+						startViewNeedsValidations = true;
+					slideTargets.push(startView);
+				}
+			}
+			
+			if (endView)
+			{
+				endViewProps = { cacheAsBitmap:endView.cacheAsBitmap,
+					opaqueBackground:endView.opaqueBackground};
+				
+				endView.cacheAsBitmap = true;
+				
+				// If the endView has an opaque background color, set that as the 
+				// opaqueBackground property to improve performance.
+				if (endView.getStyle("backgroundAlpha") >= 1)
+					endView.opaqueBackground = endView.getStyle("backgroundColor");
+				
+				if( endView is SkinnableContainer )
+				{
+					if (SkinnableContainer(endView).contentGroup)
+					{
+					endViewProps.cgIncludeInLayout = SkinnableContainer(endView).contentGroup.includeInLayout;
+					SkinnableContainer(endView).contentGroup.includeInLayout = false;
+					}
+				}
+				
+				if (mode != SlideViewTransitionMode.UNCOVER)
+				{
+					if (endView.transformRequiresValidations())
+						endViewNeedsValidations = true;
+					slideTargets.push(endView);
+				}
+				
+				//            if (mode == SlideViewTransitionMode.UNCOVER)
+				//                setComponentChildIndex(endView, navigator, 0);
+			}
+			
+			var slideDistance:Number;
+			var slideOffset:Number = 0;
+			var animatedProperty:String;
+			var verticalTransition:Boolean;
+			
+			// Predetermine slide direction and distance.
+			switch (direction)
+			{                       
+				case ViewTransitionDirection.DOWN:
+					animatedProperty = "$y";
+					slideDistance = navigator.height;
+					slideOffset = -navigator.contentGroup[animatedProperty];
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.UP:
+					animatedProperty = "$y";
+					slideDistance = -navigator.height;
+					slideOffset = navigator.contentGroup[animatedProperty];
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.RIGHT:
+					animatedProperty = "$x";
+					slideDistance = navigator.width;
+					break;
+				
+				case ViewTransitionDirection.LEFT:
+				default:
+					animatedProperty = "$x";
+					slideDistance = -navigator.width;
+					break;
+			}
+			
+			// Position the end view prior to start of transition.
+			if (mode != SlideViewTransitionMode.UNCOVER)
+				endView[animatedProperty] = -slideDistance - slideOffset;
+			
+			// Construction animation sequence.
+			var animation:Move = new Move();
+			animation.targets = slideTargets;
+			animation.duration = duration;
+			animation.easer = easer;
+			if (verticalTransition)
+				animation.yBy = slideDistance + slideOffset;
+			else
+				animation.xBy = slideDistance + slideOffset;
+			if (startViewNeedsValidations || endViewNeedsValidations)
+				animation.addEventListener("effectUpdate", effectUpdateHandler);
+			moveEffect = animation;
+			return animation;
+		}
+		
+		private function effectUpdateHandler(e:Event):void
+		{
+			// Note that the calls to validateDisplayList here should
+			// really only result in validateMatrix, which is fairly
+			// lightweight.
+			if (startViewNeedsValidations)
+				startView.validateDisplayList();
+			if (endViewNeedsValidations)
+				endView.validateDisplayList();
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override protected function createConsolidatedEffect():IEffect
+		{        
+			// Prepare our start and end view elements by positioning them prior to 
+			// the start of our transition, ensuring that they are cached as 
+			// surfaces, and adjust z-order if necessary.
+			var slideTargets:Array = new Array();
+			
+			endViewNeedsValidations = false;
+			startViewNeedsValidations = false;
+			
+			// Remove the navigator's contentGroup from layout
+			navigatorProps.navigatorContentGroupIncludeInLayout = navigator.contentGroup.includeInLayout;
+			navigator.contentGroup.includeInLayout = false;
+			
+			// Check if the navigator is a child of TabbedViewNavigator, if so
+			// remove the contentGroup from layout.
+			if (tabBar)
+			{
+				navigatorProps.topNavigatorContentGroupIncludeInLayout = targetNavigator.contentGroup.includeInLayout;
+				targetNavigator.contentGroup.includeInLayout = false;
+			}
+			
+			transitionGroup = new Group();
+			transitionGroup.includeInLayout = false;
+			
+			// Add the necessary views to the slide targets array.  When in PUSH mode,
+			// both start and end views are added.
+			if (startView && mode == SlideViewTransitionMode.PUSH)
+			{
+				if (startView.transformRequiresValidations())
+					startViewNeedsValidations = true;
+				slideTargets.push(startView);
+			}
+			
+			if (mode != SlideViewTransitionMode.UNCOVER)
+			{
+				if (endView.transformRequiresValidations())
+					endViewNeedsValidations = true;
+				slideTargets.push(endView);
+			}
+			
+			// Ensure the views are in the right stacking order based on our
+			// transition mode (cover vs. uncover for instance).
+			if (mode == SlideViewTransitionMode.COVER)
+			{
+				// When doing a cover animation, the transition group is added to the bottom
+				// of the main navigator's skin with a bitmap image of the previous state.  The
+				// end view and ui controls will then animate on top of this image to create
+				// the cover effect.
+				addComponentToContainerAt(transitionGroup, targetNavigator.skin, 0);
+				addCachedElementToGroup(transitionGroup, cachedNavigator, cachedNavigatorGlobalPosition);
+			}
+			else if (mode == SlideViewTransitionMode.UNCOVER)
+			{
+				// When doing an uncover transition, we want the real tabBar to be under the cached
+				// bitmap of the original navigator when the tabBar visibility or overlayControls
+				// mode changes.  When the tabBar isn't animating, we want the image to animate
+				// underneath the real tabBar.
+				if (animateTabBar)
+					addComponentToContainer(transitionGroup, targetNavigator.skin);
+				else
+					addComponentToContainer(transitionGroup, navigator.skin);
+				
+				startView.visible = false;
+			}
+			else
+			{
+				// Add the transition group to the top of the skin
+				addComponentToContainer(transitionGroup, targetNavigator.skin);
+			}
+			
+			if (actionBar)
+			{
+				if (mode != SlideViewTransitionMode.UNCOVER)
+					slideTargets.push(actionBar);
+				
+				navigatorProps.actionBarIncludeInLayout = actionBar.includeInLayout;
+				actionBar.includeInLayout = false;
+				
+				navigatorProps.actionBarCacheAsBitmap = actionBar.cacheAsBitmap;
+				actionBar.cacheAsBitmap = true;
+			}
+			
+			if (mode == SlideViewTransitionMode.COVER)
+			{
+				// Hide the start view since we have a cached image of the initial
+				// navigator state.
+				startViewProps = {visible: startView.visible};
+				startView.visible = false;
+			}
+			else if (startView)
+			{
+				// Store the position of the startView
+				navigatorProps.startViewX = startView.x;
+				navigatorProps.startViewY = startView.y;
+				
+				var globalPoint:Point = getTargetNavigatorCoordinates(startView);
+				
+				var delta:int = globalPoint.x - cachedStartViewGlobalPosition.x;
+				if (delta != 0)
+					startView.x -= delta;
+				
+				delta = globalPoint.y - cachedStartViewGlobalPosition.y;
+				if (delta != 0)
+					startView.y -= delta;
+				
+				if( startView is SkinnableContainer )
+				{
+				navigatorProps.startViewCacheAsBitmap = SkinnableContainer( startView ).contentGroup.cacheAsBitmap;
+				SkinnableContainer( startView ).contentGroup.cacheAsBitmap = true;
+				}
+			}
+			
+			if (endView is SkinnableContainer)
+			{
+				navigatorProps.endViewCacheAsBitmap = SkinnableContainer(endView).contentGroup.cacheAsBitmap;
+				SkinnableContainer(endView).contentGroup.cacheAsBitmap = true;
+			}
+			
+			if (cachedActionBar)
+			{
+				cachedActionBar.includeInLayout = false;
+				addCachedElementToGroup(transitionGroup, cachedActionBar, cachedActionBarGlobalPosition);
+			}
+			
+			if (tabBar)
+			{
+				// Cache the tabBar as bitmap for performance
+				navigatorProps.tabBarCacheAsBitmap = tabBar.cacheAsBitmap;
+				tabBar.cacheAsBitmap = true;
+				
+				if (animateTabBar)
+				{
+					navigatorProps.tabBarIncludeInLayout = tabBar.includeInLayout;
+					tabBar.includeInLayout = false;
+					
+					if (mode != SlideViewTransitionMode.UNCOVER)
+					{
+						slideTargets.push(tabBar);
+						
+						// When Uncovering, the cachedTabBar is not needed because the transition
+						// animates a cachedBitamp
+						if (cachedTabBar)
+						{
+							cachedTabBar.includeInLayout = false;
+							addCachedElementToGroup(transitionGroup, cachedTabBar, cachedTabBarGlobalPosition);
+						}
+					}
+				}
+			}
+			
+			var slideDistance:Number;
+			var animatedProperty:String;
+			var verticalTransition:Boolean;
+			
+			// Predetermine slide direction and distance.
+			switch (direction)
+			{           
+				case ViewTransitionDirection.RIGHT:
+					animatedProperty = "x";
+					slideDistance = targetNavigator.width;
+					break;
+				
+				case ViewTransitionDirection.DOWN:
+					animatedProperty = "y";
+					slideDistance = targetNavigator.height;
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.UP:
+					animatedProperty = "y";
+					slideDistance = -targetNavigator.height;
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.LEFT:
+				default:
+					animatedProperty = "x";
+					slideDistance = -targetNavigator.width;
+					break;
+			}
+			
+			// Position the elements of the animation
+			if (mode != SlideViewTransitionMode.UNCOVER)
+			{
+				endView[animatedProperty] = -slideDistance + endView[animatedProperty];
+				
+				if (actionBar)
+					actionBar[animatedProperty] = -slideDistance + actionBar[animatedProperty];
+				
+				if (animateTabBar)
+					tabBar[animatedProperty] = -slideDistance + tabBar[animatedProperty];
+			}
+			else
+			{
+				if (cachedNavigator)
+				{
+					cachedNavigator.includeInLayout = false;
+					addCachedElementToGroup(transitionGroup, cachedNavigator, cachedNavigatorGlobalPosition);
+				}
+			}
+			
+			// Validate to ensure our snapshots are rendered.
+			transitionGroup.validateNow();
+			
+			// Add the cached images to the display list.  This has to occur after the validation
+			// so that the displayObjects for the bitmaps are created.  Otherwise the displayObject
+			// property will be null.
+			if (cachedActionBar && mode != SlideViewTransitionMode.COVER)
+				slideTargets.push(cachedActionBar.displayObject);
+			
+			if (cachedTabBar && mode == SlideViewTransitionMode.PUSH)
+				slideTargets.push(cachedTabBar.displayObject);
+			
+			if (cachedNavigator && mode == SlideViewTransitionMode.UNCOVER)
+				slideTargets.push(cachedNavigator.displayObject);
+			
+			// Construct animation sequence.
+			var animate:Animate = new Animate();
+			var vector:Vector.<MotionPath> = new Vector.<MotionPath>();
+			vector.push(new SimpleMotionPath(animatedProperty, null, null, slideDistance));
+			animate.motionPaths = vector;
+			animate.duration = duration;
+			animate.easer = easer;
+			animate.targets = slideTargets;
+			if (startViewNeedsValidations || endViewNeedsValidations)
+				animate.addEventListener("effectUpdate", effectUpdateHandler);
+			consolidatedEffect = animate;
+			return animate;
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override protected function cleanUp():void
+		{
+			// Clear the scrollRect that the transition applied to the navigator
+			if (navigatorProps.scrollRectSet)
+				navigator.scrollRect = null;
+			
+			if (startView)
+			{
+				startView.includeInLayout = startViewProps.includeInLayout;
+				startView.visible = startViewProps.visible;
+				startView.cacheAsBitmap = startViewProps.cacheAsBitmap;
+				startView.opaqueBackground = startViewProps.opaqueBackground;
+			}
+			
+			// Restore original saved properties for includeInLayout and cacheAsBitmap.
+			if (!consolidatedTransition)
+			{
+				if (startView)
+				{
+					startView.x = startViewProps.x;
+					startView.y = startViewProps.y;
+					
+					if (startView is SkinnableContainer && SkinnableContainer(startView).contentGroup)
+						SkinnableContainer(startView).contentGroup.includeInLayout = startViewProps.cgIncludeInLayout;
+				}
+				
+				if (endView)
+				{
+					endView.cacheAsBitmap = endViewProps.cacheAsBitmap;
+					endView.opaqueBackground = endViewProps.opaqueBackground;
+					
+					if (endView is SkinnableContainer && SkinnableContainer(endView).contentGroup)
+						SkinnableContainer(endView).contentGroup.includeInLayout = endViewProps.cgIncludeInLayout;
+					
+					endViewProps = null;
+				}
+				
+				if (moveEffect)
+					moveEffect.removeEventListener("effectUpdate", effectUpdateHandler);
+				moveEffect = null;
+			}
+			else
+			{
+				if (tabBar)
+				{
+					tabBar.includeInLayout = navigatorProps.tabBarIncludeInLayout;
+					tabBar.cacheAsBitmap = navigatorProps.tabBarCacheAsBitmap;
+					targetNavigator.contentGroup.includeInLayout = navigatorProps.topNavigatorContentGroupIncludeInLayout;
+				}
+				
+				if (actionBar)
+				{
+					actionBar.includeInLayout = navigatorProps.actionBarIncludeInLayout;
+					actionBar.cacheAsBitmap = navigatorProps.actionBarCacheAsBitmap;
+				}
+				
+				if (startView)
+				{
+					if( startView is SkinnableContainer ) SkinnableContainer(startView).contentGroup.cacheAsBitmap = navigatorProps.startViewCacheAsBitmap;
+					startView.setLayoutBoundsPosition(navigatorProps.startViewX, navigatorProps.startViewY);
+					startView.visible = true;
+				}
+				
+				if (endView is SkinnableContainer)
+				{
+					SkinnableContainer(endView).contentGroup.cacheAsBitmap = navigatorProps.endViewCacheAsBitmap;
+				}
+				
+				navigator.contentGroup.includeInLayout = navigatorProps.navigatorContentGroupIncludeInLayout;
+				
+				if (transitionGroup)
+				{
+					if (mode == SlideViewTransitionMode.UNCOVER)
+					{
+						if (animateTabBar)
+							removeComponentFromContainer(transitionGroup, targetNavigator.skin);
+						else
+							removeComponentFromContainer(transitionGroup, navigator.skin);
+						
+					}
+					else
+					{
+						removeComponentFromContainer(transitionGroup, targetNavigator.skin);
+					}
+				}
+				consolidatedEffect.removeEventListener("effectUpdate", effectUpdateHandler);
+				consolidatedEffect = null;
+			}
+			
+			transitionGroup = null;
+			cachedNavigator = null;
+			cachedActionBar = null;
+			cachedTabBar = null;
+			startViewProps = null;
+			
+			super.cleanUp();
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override public function prepareForPlay():void
+		{
+			actionBarTransitionDirection = direction;
+			applyScrollRect();
+			
+			super.prepareForPlay();
+		}
+		
+		/**
+		 *  @private
+		 *  Utility function that converts a components position to the coordinate space
+		 *  of the targetNavigator.  This method doesn't use stage coordinates because
+		 *  that would return inaccurate results when dpi scaling is enabled.
+		 */
+		private function getTargetNavigatorCoordinates(component:IVisualElement):Point
+		{
+			var stagePoint:Point = DisplayObject(component).localToGlobal(new Point());
+			return targetNavigator.globalToLocal(stagePoint);
+		}
+		
+		/**
+		 *  @private
+		 *  This method sets the scrollRect of the navigator that is being animated.
+		 *  An mx_internal method was created to avoid any issues that may arise by
+		 *  adding this functionality in the Flex 4.5.1 dot release.  Developers
+		 *  can override this method to do nothing to revert to previous implementations.
+		 *  This method was added to support clipping of Views during a view transition.
+		 */
+		// TODO (chiedozi): Eventually get rid of this method
+		mx_internal function applyScrollRect():void
+		{
+			// When the initial view of the animation has tabBarVisible set to false,
+			// and the end view has it set to true, the height of the navigator
+			// will be altered to fit the actionBar.  Since the startView is not included in
+			// layout, its height will actually be larger than the navigator's.  To prevent
+			// the start view from being incorrectly clipped, the scrollRect's height
+			// is set to the maximum of the navigator's initial and current height.
+			if (!navigator.scrollRect)
+			{
+				navigatorProps.scrollRectSet = true;
+				navigator.scrollRect = new Rectangle(0, 0, navigator.width, Math.max(navigator.height, navigatorProps.initialHeight));
+			}
+		}
+	}
+}

Added: incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/ViewTransitionBase.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/ViewTransitionBase.as?rev=1230830&view=auto
==============================================================================
--- incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/ViewTransitionBase.as (added)
+++ incubator/flex/whiteboard/tink/iview/src/org/apache/spark/transitions/ViewTransitionBase.as Thu Jan 12 23:15:17 2012
@@ -0,0 +1,1670 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2010 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.spark.transitions
+{
+	
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.display.Stage;
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.geom.Matrix;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	import mx.core.FlexGlobals;
+	import mx.core.IVisualElementContainer;
+	import mx.core.UIComponent;
+	import mx.core.mx_internal;
+	import mx.effects.IEffect;
+	import mx.effects.Parallel;
+	import mx.events.EffectEvent;
+	import mx.events.FlexEvent;
+	import mx.geom.TransformOffsets;
+	import mx.managers.SystemManager;
+	
+	import spark.components.ActionBar;
+	import spark.components.Group;
+	import spark.components.TabbedViewNavigator;
+	import spark.components.supportClasses.ButtonBarBase;
+	import spark.effects.Animate;
+	import spark.effects.Fade;
+	import spark.effects.animation.MotionPath;
+	import spark.effects.animation.SimpleMotionPath;
+	import spark.effects.easing.IEaser;
+	import spark.effects.easing.Sine;
+	import spark.primitives.BitmapImage;
+	import spark.transitions.ViewTransitionDirection;
+	import spark.utils.BitmapUtil;
+	import org.apache.spark.components.supportClasses.ViewNavigatorBase;
+	import org.apache.spark.components.ViewNavigator;
+	import org.apache.spark.components.IView;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  Dispatched when the transition starts.
+	 * 
+	 *  @eventType mx.events.FlexEvent.TRANSITION_START
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 2.5
+	 *  @productversion Flex 4.5
+	 */
+	[Event(name="transitionStart", type="mx.events.FlexEvent")]
+	
+	/**
+	 *  Dispatched when the transition completes.
+	 * 
+	 *  @eventType mx.events.FlexEvent.TRANSITION_START
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 2.5
+	 *  @productversion Flex 4.5
+	 */
+	[Event(name="transitionEnd", type="mx.events.FlexEvent")]
+	
+	
+	/**
+	 *  The ViewTransitionBase class is the base class for all view transitions.  
+	 *  It is not intended to be used as a transition on its own.
+	 *  In addition to providing common convenience and helper methods used by 
+	 *  view transitions, this class provides a default action bar transition 
+	 *  sequence.
+	 * 
+	 *  <p>When a view transition is initialized, the owning view navigator 
+	 *  sets the <code>startView</code> and <code>endView</code> properties 
+	 *  to the views the transition animates. 
+	 *  The <code>navigator</code> property is 
+	 *  set to the view navigator.</p>
+	 * 
+	 *  <p>The lifecycle of a transition is as follows:</p>
+	 *    <ul>
+	 *      <li>The transition starts with 
+	 *        the <code>captureStartValues()</code> method.  
+	 *        When this method is called, the navigator is currently in the 
+	 *        start state.  
+	 *        At this time, the transition should capture any start values 
+	 *        or bitmaps that it requires. </li>
+	 *      <li>A validation pass is performed on the pending 
+	 *        view, and the <code>captureEndValues()</code> method is called. 
+	 *        At this time, the transition captures any properties or 
+	 *        bitmaps representations from the pending view.</li    >
+	 *      <li>The <code>prepareForPlay()</code> method is then called, 
+	 *        which allows the transition to perform any further preparations,
+	 *        such as preparing a Spark effects sequence, 
+	 *        or positioning transient elements on the display list.</li>
+	 *      <li>After a final validation pass, if necessary, 
+	 *        the <code>play()</code> method is called by the navigator 
+	 *        to perform the actual transition.</li>
+	 *      <li>Prior to any animation starting, the <code>start</code> 
+	 *        event is dispatched.</li>
+	 *      <li>When a transition completes, it dispatches an 
+	 *        <code>end</code> event.</li>
+	 *    </ul>
+	 *
+	 *  <p><strong>Note:</strong>Create and configure view transitions in ActionScript;
+	 *  you cannot create them in MXML.</p>
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 2.5
+	 *  @productversion Flex 4.5
+	 */
+	public class ViewTransitionBase extends EventDispatcher 
+	{
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constants
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constant used in tandem with the actionBarTransitionMode property to 
+		 *  hint the default action bar transition behavior.
+		 */
+		mx_internal static const ACTION_BAR_MODE_FADE:String = "fade";
+		
+		/**
+		 *  Constant used in tandem with the actionBarTransitionMode property to 
+		 *  hint the default action bar transition behavior.
+		 */
+		mx_internal static const ACTION_BAR_MODE_FADE_AND_SLIDE:String = "fadeAndSlide";
+		
+		/**
+		 *  Constant used in tandem with the actionBarTransitionMode property to 
+		 *  hint the default action bar transition behavior.
+		 */
+		mx_internal static const ACTION_BAR_MODE_NONE:String = "none";
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function ViewTransitionBase()
+		{
+			super();
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Flag set when we've determined that we need to transition the navigator
+		 *  in its entirety and cannot transition the control bars independently.
+		 */
+		protected var consolidatedTransition:Boolean = false;
+		
+		/**
+		 *  @private
+		 *  startView's action bar height.
+		 */ 
+		private var cachedActionBarHeight:Number;
+		
+		/**
+		 *  @private
+		 *  startView's action bar width.
+		 */ 
+		private var cachedActionBarWidth:Number;
+		
+		/**
+		 *  @private
+		 *  Transient display object used to hold temporary bitmap snapshots
+		 *  during transition.
+		 */ 
+		private var transitionGroup:Group;
+		
+		/**
+		 *  @private
+		 *  Flag to assist with cleanup of any constructs used only for vertical
+		 *  transitions (e.g. clipping masks).
+		 */ 
+		private var verticalTransition:Boolean;
+		
+		/**
+		 *  @private
+		 *  Flag used to determine whether the transition should wait a frame when
+		 *  it receives the EFFECT_END event.  This is true by default.  It is only
+		 *  set to false when the endTransitions() method is called.
+		 */ 
+		private static var renderLastFrame:Boolean = true;
+		
+		/**
+		 *  @private
+		 *  Private vector that stores all the active transitions.
+		 */ 
+		private static var activeTransitions:Vector.<ViewTransitionBase> = new Vector.<ViewTransitionBase>();
+		
+		/**
+		 *  @private
+		 *  Ends all currently active view transitions.
+		 */ 
+		mx_internal static function endTransitions():void
+		{
+			// Prevent the transitions from waiting a frame when they receive the
+			// EFFECT_END event.  See effectComplete().
+			renderLastFrame = false;
+			
+			// End all active transitions.  They will be removed from the vector
+			// in transitionComplete().
+			for (var i:int = 0; i < activeTransitions.length; i++)
+				activeTransitions[i].effect.end();
+			
+			// Restore render flag
+			renderLastFrame = true;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  duration
+		//----------------------------------
+		
+		private var _duration:Number = 250;
+		
+		/**
+		 *  Duration of the transition, in milliseconds. 
+		 *  The default may vary depending on the transition
+		 *  but is defined in ViewTransitionBase as 250 ms.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get duration():Number
+		{
+			return _duration;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set duration(value:Number):void
+		{
+			_duration = value;
+		}
+		
+		//----------------------------------
+		//  easer
+		//----------------------------------
+		
+		private var _easer:IEaser = new Sine(.5);
+		
+		/**
+		 *  The easing behavior for this transition. The IEaser object is
+		 *  generally propagated to the IEffect instance managing the actual
+		 *  transition animation.
+		 * 
+		 *  @default Sine(.5);
+		 *
+		 *  @see spark.effects.easing
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get easer():IEaser
+		{
+			return _easer;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set easer(value:IEaser):void
+		{
+			_easer = value;
+		}
+		
+		//----------------------------------
+		//  effect
+		//----------------------------------
+		
+		private var _effect:IEffect;
+		
+		/**
+		 *  Provides access to the underlying IEffect instance which the 
+		 *  transition is using to perform the transition (if any).  This property 
+		 *  is only valid after the FlexEvent.TRANSITION_START event even has been 
+		 *  dispatched.
+		 *
+		 *  If a transition does not make use of IEffect to perform the transition
+		 *  this can be null.
+		 * 
+		 *  @default null
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		mx_internal function get effect():IEffect
+		{
+			return _effect;
+		}
+		
+		mx_internal function set effect(value:IEffect):void
+		{
+			_effect = value;
+		}
+		
+		//----------------------------------
+		//  endView
+		//----------------------------------
+		
+		private var _endView:UIComponent;
+		
+		/**
+		 *  The view that the navigator is transitioning
+		 *  to, as set by the owning ViewNavigator object.  
+		 *  This property can be null.
+		 *
+		 *  @default null
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get endView():UIComponent
+		{
+			return _endView;
+		}
+		
+		/**
+		 *  @private
+		 */ 
+		public function set endView(value:UIComponent):void
+		{
+			_endView = value;
+		}
+		
+		//----------------------------------
+		//  navigator
+		//----------------------------------
+		
+		private var _navigator:ViewNavigator;
+		
+		/**
+		 *  Reference to the owning ViewNavigator instance set by the owning
+		 *  ViewNavigator.
+		 * 
+		 *  @default null
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get navigator():ViewNavigator
+		{
+			return _navigator;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set navigator(value:ViewNavigator):void
+		{
+			_navigator = value;
+		}
+		
+		//----------------------------------
+		//  startView
+		//----------------------------------
+		
+		private var _startView:UIComponent;
+		
+		/**
+		 *  The currently active view of the view navigator, 
+		 *  as set by the owning view navigator. 
+		 *  This property can be null.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get startView():UIComponent
+		{
+			return _startView;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set startView(value:UIComponent):void
+		{
+			_startView = value;
+		}
+		
+		//----------------------------------
+		//  suspendBackgroundProcessing
+		//----------------------------------
+		
+		private var _suspendBackgroundProcessing:Boolean = true;
+		
+		/**
+		 *  When set to <code>true</code>, the <code>UIComponent.suspendBackgroundProcessing()</code>
+		 *  method is invoked prior to the transition playing. 
+		 *  This disables Flex's layout manager and improving performance. 
+		 *  Upon completion of the transition,
+		 *  the layout manager function is restored by a call to the 
+		 *  <code>UIComponent.resumeBackgroundProcessing()</code> method. 
+		 *
+		 *  @default false
+		 *
+		 *  @see mx.core.UIComponent#suspendBackgroundProcessing()
+		 *  @see mx.core.UIComponent#resumeBackgroundProcessing()
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get suspendBackgroundProcessing():Boolean
+		{
+			return _suspendBackgroundProcessing;
+		}
+		
+		/**
+		 *  @private
+		 */ 
+		public function set suspendBackgroundProcessing(value:Boolean):void
+		{
+			_suspendBackgroundProcessing = value;
+		}
+		
+		//----------------------------------
+		//  transitionControlsWithContent
+		//----------------------------------
+		
+		private var _transitionControlsWithContent:Boolean;
+		
+		/**
+		 *  When set to <code>true</code>, the primary view transition
+		 *  is used to transition the view navigator in its entirety, 
+		 *  including the action bar.
+		 *  Specific transitions for the action bar are not performed.
+		 *  Because the tab bar is associated with the entire application, 
+		 *  and not a view, view transitions do not affect it.
+		 *
+		 *  <p>Note that even when set to <code>false</code>, there are cases
+		 *  where its not feasible to transition the action bar. 
+		 *  For example, when the action bar does not exist in one of 
+		 *  the two views, or if the action bar changes size.</p>
+		 *
+		 *  @default false
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function get transitionControlsWithContent():Boolean
+		{
+			return _transitionControlsWithContent;
+		}
+		
+		/**
+		 *  @private
+		 */ 
+		public function set transitionControlsWithContent(value:Boolean):void
+		{
+			_transitionControlsWithContent = value;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Private Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  actionBarTransitionMode
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Convenience property used by ViewTransitionBase overrides to hint the behavior of
+		 *  the default action bar transition as appropriate for the type and nature
+		 *  of the specific view transition. Can be one either ViewTransitionBase.ACTION_BAR_MODE_FADE, 
+		 *  ViewTransitionBase.ACTION_BAR_MODE_FADE_AND_SLIDE, or null. If set to fade 
+		 *  and slide, the actionBarTransitionDirection property is considered by the 
+		 *  default createActionBarEffect() implementation.
+		 *
+		 *  @default ACTION_BAR_MODE_FADE_AND_SLIDE
+		 */
+		mx_internal var actionBarTransitionMode:String = ACTION_BAR_MODE_FADE_AND_SLIDE;
+		
+		//----------------------------------
+		//  actionBarTransitionDirection
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Convenience property used by ViewTransitionBase overrides to hint the direction 
+		 *  of the default action bar transition when the actionBarTransitionMode is set to 
+		 *  "fadeAndSlide". Can be or null or set to one of the ViewTransitionDirection
+		 *  constants.  This property is considered by the default createActionBarEffect() 
+		 *  implementation. 
+		 *
+		 *  @default ViewTransitionDirection.LEFT
+		 */
+		mx_internal var actionBarTransitionDirection:String = ViewTransitionDirection.LEFT;
+		
+		//----------------------------------
+		//  cachedNavigatorSnapshot
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Cached image of the cumulative view of the owning navigator
+		 *  captured by the default captureStartValues() implementation.
+		 *  This snapshot is generally leveraged by transitions that need to
+		 *  performing a full screen transition.
+		 */
+		mx_internal var cachedNavigator:BitmapImage;
+		
+		/**
+		 *  @private
+		 *  Stores the location of the cached navigator in the global coordinate space
+		 *  so that the transition can properly position it when added to the display list.
+		 */ 
+		mx_internal var cachedNavigatorGlobalPosition:Point = new Point();
+		
+		//----------------------------------
+		//  cachedActionGroupSnapshot
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Cached image of the action bar's action group. This image is 
+		 *  only captured by default if action group content exists in the
+		 *  previous view.
+		 */
+		mx_internal var cachedActionGroup:BitmapImage;
+		
+		/**
+		 *  @private
+		 *  Stores the location of the cached navigator in the global coordinate space
+		 *  so that the transition can properly position it when added to the display list.
+		 */ 
+		mx_internal var cachedActionGroupGlobalPosition:Point = new Point();
+		
+		//----------------------------------
+		//  cachedTitleGroupSnapshot
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Cached image of the action bar's title group. This image is 
+		 *  only captured by default if title group content exists in the
+		 *  previous view.
+		 */
+		mx_internal var cachedTitleGroup:BitmapImage;
+		
+		/**
+		 *  @private
+		 *  Stores the location of the cached navigator in the global coordinate space
+		 *  so that the transition can properly position it when added to the display list.
+		 */ 
+		mx_internal var cachedTitleGroupGlobalPosition:Point = new Point();
+		
+		//----------------------------------
+		//  cachedNavigationGroupSnapshot
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Cached image of the action bar's navigation group. This image is 
+		 *  only captured by default if navigation group content exists in the
+		 *  previous view.
+		 */
+		mx_internal var cachedNavigationGroup:BitmapImage;
+		
+		/**
+		 *  @private
+		 *  Stores the location of the cached navigator in the global coordinate space
+		 *  so that the transition can properly position it when added to the display list.
+		 */ 
+		mx_internal var cachedNavigationGroupGlobalPosition:Point = new Point();
+		
+		//----------------------------------
+		//  targetNavigator
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Convenience property which caches our primary containing navigator, 
+		 *  this is usually our owning ViewNavigator but may be an outer TabNavigator
+		 */
+		protected var targetNavigator:ViewNavigatorBase;
+		
+		//----------------------------------
+		//  parentNavigator
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Convenience property which caches our primary containing navigator, 
+		 *  this is usually our owning ViewNavigator but may be an outer TabNavigator
+		 */
+		protected var parentNavigator:ViewNavigatorBase;
+		
+		//----------------------------------
+		//  actionBar
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 *  Convenience property which caches our associated action bar. 
+		 */
+		protected var actionBar:ActionBar;
+		
+		/**
+		 *  @private
+		 *  Convenience property which caches our associated tab bar.
+		 */
+		protected var tabBar:ButtonBarBase;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		mx_internal function preInit():void
+		{
+			// Override
+		}
+		
+		/**
+		 *  Called by the ViewNavigator during the preparation phase of a transition.
+		 *  It is invoked when the new view has been fully realized and validated and the 
+		 *  action bar and tab bar content reflect the state of the new view. 
+		 *  The transition can use this method capture any values it requires from the 
+		 *  pending view. 
+		 *  Any bitmaps reflecting the state of the new view, tab bar, 
+		 *  or action bar should be captured if required for animation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function captureStartValues():void
+		{
+			// Remember some common references.
+			parentNavigator = navigator.parentNavigator;
+			
+			if (parentNavigator is TabbedViewNavigator)
+			{
+				targetNavigator = parentNavigator;
+				tabBar = TabbedViewNavigator(parentNavigator).tabBar;
+			}
+			else
+			{
+				targetNavigator = navigator;
+			}
+			
+			if (navigator)
+				actionBar = navigator.actionBar;
+			
+			// Determine first if we're able to transition our control bars independently
+			// of our view content.  If we are, then capture the necessary action bar
+			// bitmap snapshots for use later by our default action bar transition.
+			if (!consolidatedTransition)
+				consolidatedTransition = !canTransitionControlBarContent();
+			
+			// Snapshot component parts of action bar in preparation for our 
+			// default action bar transition, (if appropriate).
+			if (!consolidatedTransition)
+			{
+				if (componentIsVisible(actionBar))
+				{
+					// Save bounds of action bar. 
+					cachedActionBarWidth = actionBar.width;
+					cachedActionBarHeight = actionBar.height;
+					
+					// Snapshot title content of our startView.
+					if (actionBar.titleGroup && actionBar.titleGroup.visible)
+						cachedTitleGroup = getSnapshot(actionBar.titleGroup, 4, cachedTitleGroupGlobalPosition);
+					else if (actionBar.titleDisplay
+						&& (actionBar.titleDisplay is UIComponent)
+						&& UIComponent(actionBar.titleDisplay).visible)
+						cachedTitleGroup = getSnapshot(UIComponent(actionBar.titleDisplay), 4, cachedTitleGroupGlobalPosition);
+					
+					// Snapshot actionContent if it's changing between our start and end views.
+					if (IView( startView).actionContent != IView( endView).actionContent)
+						cachedActionGroup = getSnapshot(actionBar.actionGroup, 4, cachedActionGroupGlobalPosition);
+					
+					// Snapshot navigationContent if it's changing between our start and end views.
+					if (IView( startView).navigationContent != IView( endView).navigationContent)
+						cachedNavigationGroup = getSnapshot(actionBar.navigationGroup, 4, cachedNavigationGroupGlobalPosition);
+				}
+			}
+		}
+		
+		/**
+		 *  Called by the ViewNavigator during the preparation phase of a transition.
+		 *  It is invoked when the new view has been fully realized and validated and the 
+		 *  action bar and tab bar content reflect the state of the new view. 
+		 *  It is at this point that the transition can capture any values it requires from the 
+		 *  pending view. 
+		 *  In addition any bitmaps reflecting the state of the new view, tab bar, 
+		 *  or action bar should be captured, if required for animation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function captureEndValues():void
+		{
+			// One final check to determine if we will be required to perform a full
+			// (consolidated) transition.
+			if (!consolidatedTransition)
+			{
+				consolidatedTransition = 
+					((actionBar.height != cachedActionBarHeight) ||
+						(actionBar.width != cachedActionBarWidth));
+			}
+		}
+		
+		/**
+		 *  Called by the ViewNavigator when the transition 
+		 *  should begin animating.  
+		 *  At this time, the transition should dispatch a
+		 *  <code>start</code> event.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function play():void
+		{   
+			if (effect)
+			{
+				activeTransitions.push(this);
+				effect.addEventListener(EffectEvent.EFFECT_END, effectComplete);
+				
+				// Dispatch TRANSITION_START.
+				if (hasEventListener(FlexEvent.TRANSITION_START))
+					dispatchEvent(new FlexEvent(FlexEvent.TRANSITION_START));
+				
+				if (navigator && navigator.stage && navigator.stage.hasEventListener(FlexEvent.TRANSITION_START))
+					navigator.stage.dispatchEvent(new FlexEvent(FlexEvent.TRANSITION_START));
+				
+				effect.play();
+			}
+			else
+				transitionComplete();
+		}
+		
+		/**
+		 *  Called by the ViewNavigator during the preparation phase 
+		 *  of a transition.  
+		 *  This method gives the transition the chance to create and
+		 *  configure the underlying IEffect instance, or to add any transient
+		 *  elements to the display list. 
+		 *  Example transient elements include  bitmap placeholders, temporary
+		 *  containers required during the transition,  and other elements. 
+		 *  If required, a final validation pass occurs prior to  the invocation 
+		 *  of the <code>play()</code> method.
+		 * 
+		 *  <p>If it is determined that a standard transition can be initiated, 
+		 *  meaning one that transitions the control bars separately from the views, 
+		 *  the default implementation of this method constructs 
+		 *  a single Parallel effect which wraps the individual effect sequences 
+		 *  for the view transition, the action bar transition, and the tab bar transition.  
+		 *  This method uses the  methods, <code>createActionBarEffect()</code>, 
+		 *  <code>createTabBarEffect()</code>, and <code>createViewEffect()</code>.</p>
+		 * 
+		 *  <p>If <code>transitionControlsWithContent</code> is set to <code>true</code>, 
+		 *  or if it is determined that the control bars cannot be transitioned independently, 
+		 *  a single effect is created to transition the navigator in its entirety.
+		 *  In this case, only <code>createConsolidatedEffect()</code> is invoked.</p>
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function prepareForPlay():void
+		{
+			if (!consolidatedTransition)
+			{
+				effect = new Parallel();
+				
+				// Prepare action bar effect
+				if (actionBar)
+				{
+					var actionBarEffect:IEffect = createActionBarEffect();
+					if (actionBarEffect)
+						Parallel(effect).addChild(actionBarEffect);
+				}
+				
+				// Prepare tab bar effect
+				if (targetNavigator is TabbedViewNavigator)
+				{
+					if (TabbedViewNavigator(targetNavigator).tabBar)
+					{
+						var tabBarEffect:IEffect = createTabBarEffect();
+						if (tabBarEffect)
+							Parallel(effect).addChild(tabBarEffect);
+					}
+				}
+				
+				// Prepare view effect
+				var viewEffect:IEffect = createViewEffect();
+				if (viewEffect)
+					Parallel(effect).addChild(viewEffect);
+			}
+			else
+			{
+				// Prepare full transition of navigator in its entirety.
+				effect = createConsolidatedEffect();
+			}
+			
+			// Disable layout manager if requested.
+			if (suspendBackgroundProcessing)
+				UIComponent.suspendBackgroundProcessing();
+		}
+		
+		/**
+		 *  Called by the default <code>prepareForPlay()</code> implementation, 
+		 *  this method is responsible for creating the Spark effect 
+		 *  played on the action bar when the transition starts.  
+		 *  This method should be overridden by subclasses if a custom action bar 
+		 *  effect is required.  
+		 *  By default, this method returns a basic action bar effect.
+		 * 
+		 *  @return An IEffect instance serving as the action bar effect. 
+		 *  This effect is played by the default <code>play()</code> method implementation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function createActionBarEffect():IEffect
+		{
+			var transformOffsets:TransformOffsets;
+			var slideDistance:Number;
+			var animatedProperty:String;
+			
+			var actionBarSkin:UIComponent = actionBar.skin;
+			var slideTargets:Array = new Array();
+			var fadeOutTargets:Array = new Array();
+			var fadeInTargets:Array = new Array();
+			
+			// Return if we have a noop action bar transition mode.
+			if (!actionBar || actionBarTransitionMode == ACTION_BAR_MODE_NONE || 
+				!actionBarTransitionMode)
+				return null;
+			
+			transitionGroup = new Group();
+			transitionGroup.autoLayout = false;
+			transitionGroup.includeInLayout = false;
+			transitionGroup.width = actionBar.width;
+			transitionGroup.height = actionBar.height;
+			addComponentToContainer(transitionGroup, actionBarSkin);
+			
+			// Construct our parallel effect.
+			var actionBarEffect:Parallel = new Parallel();
+			
+			// Calculate the slide distance based on direction.
+			switch (actionBarTransitionDirection)
+			{           
+				case ViewTransitionDirection.RIGHT:
+					animatedProperty = "x";
+					slideDistance = -actionBar.width / 2.5;
+					break;
+				
+				case ViewTransitionDirection.DOWN:
+					animatedProperty = "y";
+					slideDistance = -actionBar.height / 2.5;
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.UP:
+					animatedProperty = "y";
+					slideDistance = actionBar.height / 2.5;
+					verticalTransition = true;
+					break;
+				
+				case ViewTransitionDirection.LEFT:
+				default:
+					animatedProperty = "x";
+					slideDistance = actionBar.width / 2.5;
+					break;
+			}
+			
+			transitionGroup.clipAndEnableScrolling = true;
+			
+			// Suppress slide if our action bar transition behavior is fade-only.
+			if (actionBarTransitionMode == ACTION_BAR_MODE_FADE)
+				slideDistance = 0;
+			
+			// If the skin has title content queue new title content for fade in.
+			if (actionBar.titleGroup || actionBar.titleDisplay)
+			{
+				var titleComponent:UIComponent = actionBar.titleGroup;
+				
+				if (!titleComponent || !titleComponent.visible)
+					titleComponent = actionBar.titleDisplay as UIComponent;
+				
+				if (titleComponent)
+				{
+					// Initialize the transformation offests
+					transformOffsets = new TransformOffsets();
+					transformOffsets[animatedProperty] = slideDistance;
+					slideTargets.push(transformOffsets);
+					
+					// Initialize titleGroup
+					titleComponent.cacheAsBitmap = true;
+					titleComponent.alpha = 0;
+					titleComponent.postLayoutTransformOffsets = transformOffsets;
+					fadeInTargets.push(titleComponent);
+					
+					// We reparent the titleComponent into the transition group so
+					// that the items are properly clipped when animating vertically
+					if (verticalTransition)
+						transitionGroup.addElementAt(titleComponent, 0);
+				}
+				
+				if (cachedTitleGroup)
+					addCachedElementToGroup(transitionGroup, cachedTitleGroup, cachedTitleGroupGlobalPosition);
+			}
+			
+			// If a cache of the navigation group exists, that means the content
+			// changed.  In this case the queue cached representation to be faded
+			// out.
+			if (cachedNavigationGroup)
+				addCachedElementToGroup(transitionGroup, cachedNavigationGroup, cachedNavigationGroupGlobalPosition);
+			
+			// If a cache of the action group exists, that means the content
+			// changed.  In this case the queue cached representation to be faded
+			// out.
+			if (cachedActionGroup)
+				addCachedElementToGroup(transitionGroup, cachedActionGroup, cachedActionGroupGlobalPosition);
+			
+			// Create fade in animations for navigationContent and actionContent
+			// of the next view.
+			if (endView)
+			{
+				if (IView( endView).navigationContent)
+				{
+					// Initialize the transformation offests
+					transformOffsets = new TransformOffsets();
+					transformOffsets[animatedProperty] = slideDistance;
+					slideTargets.push(transformOffsets);
+					
+					actionBar.navigationGroup.postLayoutTransformOffsets = transformOffsets;
+					actionBar.navigationGroup.cacheAsBitmap = true;
+					actionBar.navigationGroup.alpha = 0;
+					fadeInTargets.push(actionBar.navigationGroup);
+					
+					// We reparent the titleComponent into the transition group so
+					// that the items are properly clipped when animating vertically
+					if (verticalTransition)
+						transitionGroup.addElementAt(actionBar.navigationGroup, 0);
+				}
+				
+				if (IView( endView).actionContent)
+				{
+					// Initialize the transformation offests
+					transformOffsets = new TransformOffsets();
+					transformOffsets[animatedProperty] = slideDistance;
+					slideTargets.push(transformOffsets);
+					
+					actionBar.actionGroup.postLayoutTransformOffsets = transformOffsets;
+					actionBar.actionGroup.cacheAsBitmap = true;
+					actionBar.actionGroup.alpha = 0;
+					fadeInTargets.push(actionBar.actionGroup);
+					
+					// We reparent the titleComponent into the transition group so
+					// that the items are properly clipped when animating vertically
+					if (verticalTransition)
+						transitionGroup.addElementAt(actionBar.actionGroup, 0);
+				}
+			}
+			
+			// Ensure bitmaps are rendered prior to invocation of our effect.
+			transitionGroup.validateNow();
+			
+			
+			// Setup fade out targets
+			if (cachedTitleGroup)
+			{
+				// Initialize the transformation offests
+				transformOffsets = new TransformOffsets();
+				slideTargets.push(transformOffsets);
+				
+				cachedTitleGroup.postLayoutTransformOffsets = transformOffsets;
+				fadeOutTargets.push(cachedTitleGroup.displayObject);
+			}
+			
+			if (cachedNavigationGroup)
+			{
+				// Initialize the transformation offests
+				transformOffsets = new TransformOffsets();
+				slideTargets.push(transformOffsets);
+				
+				cachedNavigationGroup.postLayoutTransformOffsets = transformOffsets;
+				fadeOutTargets.push(cachedNavigationGroup.displayObject);
+			}
+			
+			if (cachedActionGroup)
+			{
+				// Initialize the transformation offests
+				transformOffsets = new TransformOffsets();
+				slideTargets.push(transformOffsets);
+				
+				cachedActionGroup.postLayoutTransformOffsets = transformOffsets;
+				fadeOutTargets.push(cachedActionGroup.displayObject);
+			}
+			
+			// If no fade effects we aren't animating anything so return null
+			if (fadeInTargets.length == 0 && fadeOutTargets.length == 0)
+				return null;
+			
+			// Create fade in effect
+			if (fadeInTargets.length > 0)
+			{
+				var fadeInEffect:Fade = new Fade();
+				fadeInEffect.targets = fadeInTargets;
+				fadeInEffect.duration = duration;
+				fadeInEffect.alphaFrom = 0;
+				fadeInEffect.alphaTo = 1;
+				actionBarEffect.addChild(fadeInEffect);
+			}
+			
+			// Create fade out effect
+			if (fadeOutTargets.length > 0)
+			{
+				var fadeOutEffect:Fade = new Fade();
+				fadeOutEffect.targets = fadeOutTargets;
+				fadeOutEffect.duration = duration;
+				fadeOutEffect.alphaFrom = 1;
+				fadeOutEffect.alphaTo = 0;
+				actionBarEffect.addChild(fadeOutEffect);
+			}        
+			
+			// Create slide in effect
+			var vector:Vector.<MotionPath> = new Vector.<MotionPath>();
+			vector.push(new SimpleMotionPath(animatedProperty, null, null, -slideDistance));
+			
+			var moveEffect:Animate = new Animate();
+			moveEffect.targets = slideTargets;
+			moveEffect.motionPaths = vector;
+			moveEffect.easer = new spark.effects.easing.Sine(.7);
+			moveEffect.duration = duration;
+			moveEffect.addEventListener(EffectEvent.EFFECT_UPDATE, actionBarMoveEffect_effectUpdateHandler);
+			moveEffect.addEventListener(EffectEvent.EFFECT_END, actionBarMoveEffect_effectEndedHandler);
+			actionBarEffect.addChild(moveEffect);
+			
+			return actionBarEffect;
+		}
+		
+		/**
+		 *  Called by the default <code>prepareForPlay()</code> implementation, 
+		 *  this method is responsible for creating the Spark effect played 
+		 *  on the tab bar when the transition starts.  
+		 *  This method should be overridden by subclasses.  
+		 *  By default, this returns null.
+		 * 
+		 *  @return An IEffect instance serving as the tab bar transition. 
+		 *  This effect is played by the default <code>play()</code> method implementation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function createTabBarEffect():IEffect
+		{
+			return null;
+		}
+		
+		/**
+		 *  Called by the default <code>prepareForPlay()</code> implementation, 
+		 *  this method is responsible for creating the Spark effect played 
+		 *  on the current and next view when the transition starts.  
+		 *  This method should be overridden by subclasses.  
+		 *  By default, this method returns null.
+		 * 
+		 *  @return An IEffect instance serving as the view transition. 
+		 *  This effect is played by the default <code>play()</code> method implementation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function createViewEffect():IEffect
+		{
+			return null;
+		}
+		
+		/**
+		 *  Called by the default <code>prepareForPlay()</code> implementation, 
+		 *  this method is responsible for creating the Spark effect played to
+		 *  transition the entire navigator, inclusive of the control bar content, 
+		 *  when necessary.  
+		 *  This method should be overridden by subclasses.  
+		 *  By default, this method returns null.
+		 * 
+		 *  @return An IEffect instance serving as the view transition. 
+		 *  This effect is played by the default <code>play()</code> method implementation.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function createConsolidatedEffect():IEffect
+		{
+			return null;
+		}
+		
+		/**
+		 *  Called by the transition to indicate that the transition
+		 *  has completed.
+		 *  This method dispatches the <code>end</code> event.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function transitionComplete():void
+		{
+			var stage:Stage;
+			if (navigator)
+				stage = navigator.stage;
+			
+			cleanUp();
+			
+			activeTransitions.splice(activeTransitions.indexOf(this), 1);
+			
+			if (hasEventListener(FlexEvent.TRANSITION_END))
+				dispatchEvent(new FlexEvent(FlexEvent.TRANSITION_END));
+			
+			if (stage && stage.hasEventListener(FlexEvent.TRANSITION_END))
+				stage.dispatchEvent(new FlexEvent(FlexEvent.TRANSITION_END));
+		}
+		
+		/**
+		 *  Called after the transition completes.
+		 *  This method is responsible for  releasing any references 
+		 *  and temporary constructs used by the transition.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected function cleanUp():void
+		{
+			if (!consolidatedTransition && transitionGroup)
+			{               
+				if (cachedTitleGroup)
+					transitionGroup.removeElement(cachedTitleGroup);
+				
+				if (cachedNavigationGroup)
+					transitionGroup.removeElement(cachedNavigationGroup);
+				
+				if (cachedActionGroup)
+				{
+					transitionGroup.removeElement(cachedActionGroup);
+					actionBar.actionGroup.cacheAsBitmap = false;
+				}
+				
+				if (actionBar)
+				{
+					// Restore title group and title content to their original state.
+					if (actionBar.titleGroup && actionBar.titleGroup.visible)
+					{
+						actionBar.titleGroup.postLayoutTransformOffsets = null;
+						actionBar.titleGroup.cacheAsBitmap = false;
+					}
+					
+					if (actionBar.titleDisplay 
+						&& (actionBar.titleDisplay is DisplayObject)
+						&& DisplayObject(actionBar.titleDisplay).visible)
+					{
+						(actionBar.titleDisplay as UIComponent).postLayoutTransformOffsets = null;
+						DisplayObject(actionBar.titleDisplay).cacheAsBitmap = false;
+					}
+					
+					// Restore title group and title content to their original home.
+					if (verticalTransition)
+					{
+						var titleComponent:UIComponent = actionBar.titleGroup;
+						if (!titleComponent || !titleComponent.visible)
+							titleComponent = actionBar.titleDisplay as UIComponent;
+						
+						if (titleComponent)
+						{
+							transitionGroup.removeElement(titleComponent);
+							addComponentToContainer(titleComponent, actionBar.skin);
+						}
+					}
+					
+					// Restore navigation group to their proper home.
+					if (IView( endView).navigationContent && verticalTransition)
+					{
+						transitionGroup.removeElement(actionBar.navigationGroup);
+						if (actionBar.titleDisplay)
+						{
+							var childIndex:uint = actionBar.skin.getChildIndex(actionBar.titleDisplay as DisplayObject);
+							addComponentToContainerAt(actionBar.navigationGroup, actionBar.skin, childIndex);
+						}
+						else
+							addComponentToContainer(actionBar.navigationGroup, actionBar.skin);
+					}
+					
+					// Restore action group to their proper home.
+					if (IView( endView).actionContent && verticalTransition)
+					{
+						transitionGroup.removeElement(actionBar.actionGroup);
+						if (actionBar.titleDisplay)
+						{
+							childIndex = actionBar.skin.getChildIndex(actionBar.titleDisplay as DisplayObject);
+							addComponentToContainerAt(actionBar.actionGroup, actionBar.skin, childIndex);
+						}
+						else
+							addComponentToContainer(actionBar.actionGroup, actionBar.skin);
+					}
+					
+					removeComponentFromContainer(transitionGroup, actionBar.skin);
+					
+					actionBar.skin.scrollRect = null;
+					
+					// Force actionBar to update content group positions after
+					// animating positions. If the width and height change during
+					// the transition, we need relayout it's children because 
+					// during the transition they are removed from layout and
+					// missed during the validation pass. See SDK-30142.
+					// TODO (jasonsj): Consider ending transitions when orientation
+					// changes
+					if ((actionBar.width != cachedActionBarWidth)
+						|| (actionBar.height != cachedActionBarHeight))
+					{
+						actionBar.skin.invalidateDisplayList();
+					}
+					
+					if (actionBar.actionGroup)
+						actionBar.actionGroup.postLayoutTransformOffsets = null;
+					
+					if (actionBar.navigationGroup)
+						actionBar.navigationGroup.postLayoutTransformOffsets = null;
+				}
+				
+				verticalTransition = false;
+				cachedActionBarHeight = 0;
+				cachedActionBarWidth = 0;
+				
+				transitionGroup = null;
+				cachedTitleGroup = null;
+				cachedNavigationGroup = null;
+				cachedActionGroup = null;
+			}
+			
+			consolidatedTransition = false;
+			actionBar = null;
+			tabBar = null;
+			parentNavigator = null;
+			targetNavigator = null;
+			navigator = null;
+			startView = null;
+			endView = null;
+			
+			// Re-enable layout manager if appropriate.
+			if (suspendBackgroundProcessing)
+				UIComponent.resumeBackgroundProcessing();
+		}
+		
+		/**
+		 *  Determine if Flex can perform a transition on 
+		 *  action bar or tab bar content independently of the views.
+		 * 
+		 *  <p>Flex cannot perform a transition on the control bars independently:</p>
+		 *  <ul>
+		 *      <li>If the containing view navigator is a TabbedViewNavigator 
+		 *        and its tab bar's visibility changes between views.</li>
+		 *      <li>If the value of the view navigator's <code>overlayControls</code>
+		 *        property changes between views.</li>
+		 *      <li>If the size or visibility of the action bar changes 
+		 *        between views.</li>
+		 *  </ul>
+		 * 
+		 *  @return <code>false</code> if Flex determines controls bars between views are 
+		 *  incompatible in some way.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */ 
+		protected function canTransitionControlBarContent():Boolean
+		{               
+			// Short circuit if we've already been asked to not consider
+			// control bars during transition.
+			if (transitionControlsWithContent)
+				return false;
+			
+			// Test for visibility or size of tab bar changing.
+			if (targetNavigator is TabbedViewNavigator)
+			{
+				var tabBar:ButtonBarBase = TabbedViewNavigator(targetNavigator).tabBar;
+				if (componentIsVisible(tabBar) != IView( endView).tabBarVisible)
+					return false;
+			}
+			
+			// Test for visibility or size of action bar changing.
+			if (navigator is ViewNavigator)
+			{
+				var actionBar:ActionBar = ViewNavigator(navigator).actionBar;
+				if (componentIsVisible(actionBar) != IView( endView ).actionBarVisible)
+					return false;
+			}
+			
+			// Test for valid views.
+			if (!startView || !endView)
+				return false;
+			
+			// Test for value of overlayControls changing.
+			if (IView( startView).overlayControls != IView( endView ).overlayControls)
+				return false;
+			
+			return true;
+		}
+		
+		/**
+		 *  Used to render snap shots of screen elements in 
+		 *  preparation for transitioning.  
+		 *  The bitmap is returned in the form of a BitmapImage object.
+		 *   
+		 *  <p>The BitmapImage is in target's parent coordiantes space - 
+		 *  it overlaps the target precisely if paranted to the same parent.
+		 * 
+		 *  When moving to a different parent, make sure to adjust the 
+		 *  transformation of the BitmapImage to correctly account for the
+		 *  change in coordinate spaces.
+		 * 
+		 *  The updated value of the <code>globalPosition</code> parameter
+		 *  can be used for that.</p> 
+		 * 
+		 *  @param target Display object to capture.
+		 *  
+		 *  @param padding Padding around the object to be included in 
+		 *  the BitmapImage object.
+		 * 
+		 *  @param globalPosition When non-null, <code>globalPosition</code>
+		 *  will be updated with the origin of the BitmapImage in global 
+		 *  coordiantes. When moving to a different coordinate space, this
+		 *  value can be used to adjust the snapshot's position so its
+		 *  global position on screen doesn't change. 
+		 * 
+		 *  @return BitmapImage object representing the target.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */ 
+		protected function getSnapshot(target:UIComponent, padding:int = 4, globalPosition:Point = null):BitmapImage
+		{       
+			if (!target || !target.visible || target.width == 0 || target.height == 0)
+				return null;
+			
+			var snapshot:BitmapImage = new BitmapImage();
+			
+			// Ensure bitmap leverages its own display object for performance
+			// reasons.
+			snapshot.alwaysCreateDisplayObject = true;
+			
+			// Capture image, with consideration for transform and color matrix.
+			// Return null if an error is thrown.
+			var bounds:Rectangle = new Rectangle();
+			try
+			{
+				snapshot.source = BitmapUtil.getSnapshotWithPadding(target, padding, true, bounds);
+			}
+			catch (e:SecurityError)
+			{
+				return null;
+			}
+			
+			// Size and offset snapShot to match our image bounds data.
+			snapshot.width = bounds.width;
+			snapshot.height = bounds.height;
+			
+			var m:Matrix = new Matrix();
+			m.translate(bounds.left, bounds.top);
+			
+			// Apply target's inverse concatenated matrix:
+			var parent:DisplayObjectContainer = target.parent;
+			if (parent)
+			{
+				var inverted:Matrix = parent.transform.concatenatedMatrix.clone();
+				inverted.invert();
+				m.concat(inverted);
+			}
+			snapshot.setLayoutMatrix(m, false);
+			
+			// Exclude from layout.
+			snapshot.includeInLayout = false;
+			
+			if (globalPosition)
+			{
+				var pt:Point = parent ? parent.localToGlobal(new Point(snapshot.x, snapshot.y)) : new Point();
+				globalPosition.x = pt.x;
+				globalPosition.y = pt.y;
+			}
+			
+			return snapshot; 
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Private Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Remove listeners
+		 */ 
+		private function actionBarMoveEffect_effectEndedHandler(event:EffectEvent):void
+		{
+			event.target.removeEventListener(EffectEvent.EFFECT_UPDATE, actionBarMoveEffect_effectUpdateHandler);
+			event.target.removeEventListener(EffectEvent.EFFECT_END, actionBarMoveEffect_effectEndedHandler);
+		}
+		
+		/**
+		 *  @private
+		 *  Since layout is disabled, we need to force validation on all of the
+		 *  participating display objects.
+		 */
+		private function actionBarMoveEffect_effectUpdateHandler(event:EffectEvent):void
+		{
+			if (!actionBar)
+				return;
+			
+			// This code is a temporary performance fix for transitions.  Since layout is
+			// disabled during ViewTransitions, in the past this method would call 
+			// validateDisplayList() on the animation targets to update their internal position 
+			// matrices.  We learned that this was causing a reduction in framerate due to
+			// actionScript overhead.  To workaround the issue we are moving the x and y positions
+			// of the underlying displayObjects manually.  This is a temporary fix to get
+			// our performance numbers back up after checking in a fix for SDK-30839.
+			// TODO (chiedozi): Clean up this code and use propery layout methods
+			if (verticalTransition)
+			{
+				if (actionBar.actionGroup  && actionBar.actionGroup.postLayoutTransformOffsets)
+					actionBar.actionGroup.$y = actionBar.actionGroup.y + actionBar.actionGroup.postLayoutTransformOffsets.y;
+				
+				if (actionBar.navigationGroup && actionBar.navigationGroup.postLayoutTransformOffsets)
+					actionBar.navigationGroup.$y = actionBar.navigationGroup.y + actionBar.navigationGroup.postLayoutTransformOffsets.y;
+				
+				if (actionBar.titleDisplay && UIComponent(actionBar.titleDisplay).postLayoutTransformOffsets)
+					UIComponent(actionBar.titleDisplay).$y = UIComponent(actionBar.titleDisplay).y + UIComponent(actionBar.titleDisplay).postLayoutTransformOffsets.y;
+				
+				if (actionBar.titleGroup && actionBar.titleGroup.postLayoutTransformOffsets)
+					actionBar.titleGroup.$y = actionBar.titleGroup.y + actionBar.titleGroup.postLayoutTransformOffsets.y;
+				
+				if (cachedTitleGroup && cachedTitleGroup.displayObject)
+					cachedTitleGroup.displayObject.y = cachedTitleGroup.y + cachedTitleGroup.postLayoutTransformOffsets.y;
+				
+				if (cachedNavigationGroup && cachedNavigationGroup.displayObject)
+					cachedNavigationGroup.displayObject.y = cachedNavigationGroup.y + cachedNavigationGroup.postLayoutTransformOffsets.y;
+				
+				if (cachedActionGroup && cachedActionGroup.displayObject)
+					cachedActionGroup.displayObject.y = cachedActionGroup.y + cachedActionGroup.postLayoutTransformOffsets.y;           
+			}
+			else
+			{
+				if (actionBar.actionGroup  && actionBar.actionGroup.postLayoutTransformOffsets)
+					actionBar.actionGroup.$x = actionBar.actionGroup.x + actionBar.actionGroup.postLayoutTransformOffsets.x;
+				
+				if (actionBar.navigationGroup && actionBar.navigationGroup.postLayoutTransformOffsets)
+					actionBar.navigationGroup.$x = actionBar.navigationGroup.x + actionBar.navigationGroup.postLayoutTransformOffsets.x;
+				
+				if (actionBar.titleDisplay && UIComponent(actionBar.titleDisplay).postLayoutTransformOffsets)
+					UIComponent(actionBar.titleDisplay).$x = UIComponent(actionBar.titleDisplay).x + UIComponent(actionBar.titleDisplay).postLayoutTransformOffsets.x;
+				
+				if (actionBar.titleGroup && actionBar.titleGroup.postLayoutTransformOffsets)
+					actionBar.titleGroup.$x = actionBar.titleGroup.x + actionBar.titleGroup.postLayoutTransformOffsets.x;
+				
+				if (cachedTitleGroup && cachedTitleGroup.displayObject)
+					cachedTitleGroup.displayObject.x = cachedTitleGroup.x + cachedTitleGroup.postLayoutTransformOffsets.x;
+				
+				if (cachedNavigationGroup && cachedNavigationGroup.displayObject)
+					cachedNavigationGroup.displayObject.x = cachedNavigationGroup.x + cachedNavigationGroup.postLayoutTransformOffsets.x;
+				
+				if (cachedActionGroup && cachedActionGroup.displayObject)
+					cachedActionGroup.displayObject.x = cachedActionGroup.x + cachedActionGroup.postLayoutTransformOffsets.x;
+			}
+		}
+		
+		/**
+		 * @private
+		 */ 
+		private function effectComplete(event:EffectEvent):void
+		{
+			effect.removeEventListener(EffectEvent.EFFECT_END, effectComplete);
+			
+			// Validate the last frame of the actionBar animation so that it
+			// renders properly.  We put this here because layout isn't reenabled
+			// until the next frame, meaning this validation won't be applied for
+			// two frames.
+			if (!consolidatedTransition)
+				actionBarMoveEffect_effectUpdateHandler(null);
+			
+			if (renderLastFrame)
+			{
+				// We don't call transitionComplete just yet, we want to ensure
+				// that the last frame of animation actually gets rendered on screen
+				// before we clean up after ourselves.  This prevents a perceived 
+				// stutter on the very last frame.
+				navigator.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
+			}
+			else
+			{
+				enterFrameHandler(null);
+			}
+		}
+		
+		/**
+		 * @private
+		 */ 
+		private function enterFrameHandler(event:Event):void
+		{
+			if (event)
+				navigator.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
+			
+			effect = null;
+			transitionComplete();
+		}
+		
+		/**
+		 * @private
+		 * Helper method to test whether a component is visible to user.
+		 */ 
+		mx_internal function componentIsVisible(component:UIComponent):Boolean
+		{
+			return component && component.visible && 
+				component.width && component.height && component.alpha;
+		}
+		
+		/**
+		 *  @private
+		 *  Helper method to add a UIComponent instance to either an IVisualElementContainer
+		 *  or DisplayObjectContainer. 
+		 */ 
+		mx_internal function addComponentToContainerAt(component:UIComponent, 
+													   container:UIComponent, 
+													   index:int):void
+		{
+			if (container is IVisualElementContainer)
+				IVisualElementContainer(container).addElementAt(component, index);
+			else
+				container.addChildAt(component, index);
+		}
+		
+		/**
+		 *  @private
+		 *  Helper method to add a UIComponent instance to either an IVisualElementContainer
+		 *  or DisplayObjectContainer.
+		 */ 
+		mx_internal function addComponentToContainer(component:UIComponent, 
+													 container:UIComponent):void
+		{
+			if (container is IVisualElementContainer)
+				IVisualElementContainer(container).addElement(component);
+			else
+				container.addChild(component);
+		}
+		
+		/**
+		 *  @private
+		 *  Helper method to remove a UIComponent instance from either an IVisualElementContainer
+		 *  or DisplayObjectContainer.
+		 */ 
+		mx_internal function removeComponentFromContainer(component:UIComponent, 
+														  container:UIComponent):void
+		{
+			if (container is IVisualElementContainer)
+				IVisualElementContainer(container).removeElement(component);
+			else
+				container.removeChild(component);
+		}
+		
+		/**
+		 *  @private
+		 *  Helper method to set the child index of the given component.
+		 */ 
+		mx_internal function setComponentChildIndex(component:UIComponent, 
+													container:UIComponent, 
+													index:int):void
+		{
+			if (container is IVisualElementContainer)
+				IVisualElementContainer(container).setElementIndex(component, index);
+			else
+				container.setChildIndex(component, index);
+		}
+		
+		/**
+		 *  @private
+		 *  Adds the element to the targetGroup and adjusts the position
+		 *  so that the global position remains the same.
+		 * 
+		 *  Note the targetGroup must be already added to the display list and
+		 *  positioned in order for this method to adjust the cachedElement's position
+		 *  correctly.
+		 * 
+		 *  @param targetGroup  The Group that will parent the cached element.
+		 *  @param cachedElement  The cached element - the return value of getSnapshot()
+		 *  @param cachedElementGlobalPosition The global position returned from getSnapshot()
+		 * 
+		 *  @see #getSnapshot
+		 */
+		mx_internal function addCachedElementToGroup(targetGroup:Group, 
+													 cachedElement:BitmapImage, 
+													 cachedElementGlobalPosition:Point):void
+		{
+			targetGroup.addElement(cachedElement);
+			
+			// We are moving the cachedTitleGroup to the transitionGroup's coordinate space,
+			// adjust the position
+			var localOrigin:Point = targetGroup.globalToLocal(cachedElementGlobalPosition);
+			cachedElement.x = localOrigin.x;
+			cachedElement.y = localOrigin.y;
+		}
+		
+		/**
+		 *  @private
+		 *  Helper method that returns index of the given component. 
+		 */
+		mx_internal function getComponentChildIndex(component:UIComponent, container:UIComponent):int
+		{
+			if (container is IVisualElementContainer)
+				return IVisualElementContainer(container).getElementIndex(component);
+			else
+				return container.getChildIndex(component);
+		}
+	}
+}