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);
+ }
+ }
+}