Two Examples of Layout Animations
A few folks have been asking for the source of my Creating Custom Layouts in Flex 4 talk at the Flash Camp Boston event, and I finally found the time to post it here. My apologies for the delay. Click on the image to go to the demo, right-click and select “view source” to get to the goods. This is pretty much my old WheelLayout demo, but I added a couple of animations to make things a little bit slicker:
- Clicking on any image in the WheelLayout mode will rotate all the elements until the selected item is centered in front. In this animation the layout runs on every frame of the animation.
- Selecting different layouts from the drop-down will animate the items’ transformation. In this animation the layout is disabled and is not running during the animation.
Animating the Scroll Position
In the first animation I want the selected item to come “in view”. In the WheelLayout I’ve already implemented the standard API that calculates the scroll distance to an item – getScrollPositionDeltaToElement(). Now in the item renderer of the list – FlickrThumbnail.mxml – I detect when the item has been clicked and then create an animation for the scroll position of the parent Group:
protected function itemrenderer1_clickHandler(event:MouseEvent):void { var g:GroupBase = parent as GroupBase; var p:Point = g.layout.getScrollPositionDeltaToElement(this.itemIndex); if (p) { var startX:Number = g.horizontalScrollPosition; var startY:Number = g.verticalScrollPosition; var anim:Animate = new Animate(); anim.motionPaths = new [ new SimpleMotionPath("horizontalScrollPosition", startX, startX + p.x, 500), new SimpleMotionPath("verticalScrollPosition", startY, startY + p.y, 500) ]; var interpolator:NumberInterpolatorWrapping = new NumberInterpolatorWrapping(0, g.contentWidth - g.width); var scrollLength:Number = interpolator.getLength(startX, startX + p.x); anim.interpolator = interpolator; anim.duration = Math.max(550, Math.min(2500, scrollLength * 2)); anim.play([g]); } }
One interesting thing to note is that because of the circular nature of the WheelLayout I wanted the animation to interpolate between the values in a wrap-around manner. For example scrolling from the last element to the first element shouldn’t scroll through any other elements since the first and last elements are visually next to each other. For that reason I implemented a custom interpolator – NumberInterpolatorWrapping.as.
Animating Items between Different Layouts
In this animation I wanted all the elements to move and rotate smoothly when I switch between various layouts. In this animation the start position is defined by the current layout and the end position is defined by the new layout. In-between, while the elements are being animated, they really don’t belong to any layout. For that reason, I disable the layout of the container for the duration of the animation using the autoLayout property of the parent Group.
For convenience I transition between the layouts using states:
<s:states> <s:State name="tile"/> <s:State name="wheel"/> <s:State name="vertical"/> <s:State name="horizontal"/> </s:states> <s:List width="100%" height="100%" dataProvider="{photoFeed}" itemRenderer="FlickrThumbnail" id="theList" useVirtualLayout="false"> <s:layout.vertical> <s:VerticalLayout horizontalAlign="center"/> </s:layout.vertical> <s:layout.horizontal> <s:HorizontalLayout verticalAlign="middle"/> </s:layout.horizontal> <s:layout.tile> <s:TileLayout horizontalAlign="center" verticalAlign="bottom" columnWidth="112" rowHeight="132" requestedColumnCount="5"/> </s:layout.tile> <s:layout.wheel> <my:WheelLayout gap="20" axisAngle="{axisSlider.value}" verticalCenterOffset="{offsetSlider.value}"/> </s:layout.wheel> </s:List>
Because the elements could be both moved and/or rotated in 2D or 3D, I use a parallel of both effects:
<fx:Declarations> <s:Parallel id="myEffect" effectEnd="myEffect_effectEndHandler(event)"> <s:Move3D applyChangesPostLayout="false"/> <s:Rotate3D applyChangesPostLayout="false"/> </s:Parallel> </fx:Declarations>
And finally, when I switch from one layout state to another, I want to run the effect. Now I need to perform the following steps:
- Make the effect target all of the elements.
- Capture the start values (the position and rotation defined by the old layout).
- Switch the layout (by changing the state) and call validateNow() so that all elements are positioned and/or rotated by the new layout.
- Turn off the autoLayout property so that the new layout doesn’t interfere with the running effect.
- Run the effect. Note that at this point the effect is going to capture the animation end values – the position/rotation defined by the new layout. I’ve already captured the start values at step 2, so I’m all set.
- When the effect is done, turn the layout back on.
private function animateTo(toState:String):void { // Make sure any previous animation is stopped. if (myEffect.isPlaying) myEffect.stop(); // Add targets myEffect.targets = new Array(); for (var i:int = 0; i < theList.dataGroup.numElements; i++) myEffect.targets.push(theList.dataGroup.getElementAt(i)); // Create Transition for all elements myEffect.captureStartValues(); // Go to the end state var fromState:String = this.currentState; setCurrentState(toState); // Validate everything before turning off the layout theList.validateNow(); // Turn the layout off before running the effect theList.dataGroup.autoLayout = false; // Play the effect myEffect.play(); } protected function myEffect_effectEndHandler(event:EffectEvent):void { theList.dataGroup.autoLayout = true; }
Note that my demo has one limitation – I needed to turn off virtual layout so that everything works fine. If I have virtual layout running, I’m not guaranteed that the old and new layouts will assign the items to the same item renderers.
Click on the image at the top to go to the demo, where you can select “view source” from the right-click menu to get the code.

Thanks, I was trying to solve the exact same behavior.
I have a question though: is it considered a bad practice if a layout changes the size of elements? For example, in your example if in the horizontal state all the items should be stretched vertical, what is the best approach to do that? Should the layout stretch elements or it is the container who should do that and let the layout deal with resized elements?
Hi Djam,
The layouts determine the actual size and position/transformation for all of the elements (based on any user settings + preferred/measured sizes of the ILayoutElement and the container width/height). The Spark containers delegate all of this logic to the layouts and don’t resize or position the elements.
Hi Evtim,
fantastic work, well done.
One suggestion: in terms of usability of the wheel, I thought it would be nice if the user could rotate it not only from the scrollbar but also by grabbing (click and hold) an item and moving the mouse left or right.
Best, Mario
Hi Mario,
Interesting idea – basically adding sort of touch interaction? I may give it a try when I find the time.
Thanks,
Evtim
Nice work
Is there any special license on this work? Or could I modify it and include it in my program as long as I credit you?
Thanks again!
Yeah, everything on this blog, unless explicitly stated otherwise, is licensed under Creative Common Attribution 3.0 license – there’s a link on the right hand pane of the blog. So yeah, you can modify and use in your software as long as you credit me for the original work only. Cheers!
Why don’t you use instead of changing yourself the state and playing an effect ?
sorry :
Why don’t you use S:TRANSITION instead of changing yourself the state and playing an effect ?
@Evtim
Very very good work of your WheelLayout. Regarding to usability of the wheel, please also refer to the effect of the following link:
http://theflashblog.com/flash/clickcarousel.swf,
but that is not an open source work. Please check.
Thanks.
By the way, does WheelLayout have the limitation for image file size? it seems that it will not load the image with a large size? Thanks for your response.
Hi Evtim,
Great example with impressive visual effect.
I have one simple question: how do you manage the addition or deletion of elements to the list? I.e. how can a new element be animated to get in and how can a deleted element be animated out?
In Flex 3 there was the itemsChangeEffect property, see here:
http://livedocs.adobe.com/flex/3/html/help.html?content=createeffects_5.html
Any clue as to how this could be achieved with the spark architecture?
Thx
Love the work.
I am working on a project at the moment and we have committed to the Flex SDK 4 and the Spark architecture. We have been using Flash Builder 4 since the first release and have grown and learnt how to use this great new approach to the skinning and component architecture.
It is a world away from my years with flash only development (continually making my own frameworks – if they could even be called that) and am feeling like I am now learning the correct way to tackle/plan/develop a large project.
BUT… I have spent many, many hours now trying to get the site we are developing to look and feel like flash and not like a data-driven RIA that is used for managing business logic and processes. I am really feeling like I have come all this way and am now unable to deliver (a cool looking site with finesse and easing, etc).
Evtim, can you give me some reassurance that this is not to case please. For example, I would like to make the itemRenderers in a list ease into position (or a group with a flex/custom layout) like this example: http://www.fwaphoto.com/. I have been struggling with this for some time and need help from someone who has answers to these questions.
Feel free to email me directly.
Thanks