Animating Spark List Items.

Previously in Flex 3 List Components came with a style property called the itemsChangeEffect. This allowed you to specify a sequence of effects to apply to the item renderers when a change to the dataProvider occurred.

eg.

view plain print about
1<mx:Sequence id="dataChangeEffect1">
2        <mx:Blur
3            blurYTo="12" blurXTo="12"
4            duration="300"
5            perElementOffset="150"
6            filter="removeItem"/
>

7        <mx:SetPropertyAction
8            name="visible" value="false"
9            filter="removeItem"/
>

10        <mx:UnconstrainItemAction/>
11        <mx:Parallel>
12            <mx:Move
13                duration="750"
14                easingFunction="{Elastic.easeOut}"
15                perElementOffset="20"/
>

16            <mx:RemoveItemAction
17                startDelay="400"
18                filter="removeItem"/
>

19            <mx:AddItemAction
20                startDelay="400"
21                filter="addItem"/
>

22            <mx:Blur
23                startDelay="410"
24                blurXFrom="18" blurYFrom="18" blurXTo="0" blurYTo="0"
25                duration="300"
26                filter="addItem"/
>

27        </mx:Parallel>
28    </mx:Sequence>
29
30    <!-- This TileList uses a custom data change effect. -->
31    <mx:TileList id="tlist0"
32        height="400" width="400"
33        fontSize="30" fontStyle="bold"
34        columnCount="4" rowCount="4"
35        direction="horizontal"
36        dataProvider="{myDP}"
37        allowMultipleSelection="true"
38        offscreenExtraRowsOrColumns="4"
39        itemsChangeEffect="{dataChangeEffect1}"/
>

Because I was writing a Flex 4 Application I couldn't find anything similar to this property in the Spark List components, so I decided to roll my own utilising a Custom layout for the List Component.

With the Flex 3 itemsChangeEffect you had to wait for your data to change before the effect would take place. With my effect I wanted the user to be able to drag an item around the list with the other elements moving away to allow for placement of the dragged item. Kind of like moses parting the waves with a draggable item.

Writing the custom layout:

Positioning the Elements.

Inside the custom layout it's the override of the updateDisplayList that does the hard yakka positioning and sizing the List items. It makes sure that the items x and y positions do not overlap or exceed the width of the component. In this instance the first item is in the first row and any subsequent elements are beneath this in pairs.

Drag and Drop

For this layout I still needed the the drag and drop functionality so I extended the TileLayout. If you still need the drag and drop functionality you may need to override a handful of the methods needed to calculate the dropLocations,indices and the location of the dropIndicator.

calculateDropLocation
calculateDropIndex
calculateDropCellIndex
calculateDropIndicatorBounds

Animating the elements - things to remember

With animating a Flex container you need to set the autoLayout flag to false before the animation to prevent flex from updating the containers layout after a child element is resized or repositioned. Once the animation has finished the autoLayout flag can be set back to it's default value of true.

view plain print about
1override public function updateDisplayList(width:Number, height:Number):void{
2    
3    ...
4        
5    if(animate){
6        
7        target.autoLayout = false;
8        target.validateNow();
9        
10        var trans:Parallel = new Parallel(target);    
11
12        trans.addEventListener(EffectEvent.EFFECT_END,onTransitionEnd);            
13        trans.play();
14        
15    }
16    
17}
18
19private function onTransitionEnd(e:EffectEvent):void{        
20    
21    e.target.removeEventListener(EffectEvent.EFFECT_END,onTransitionEnd);
22    target.autoLayout = true;
23    
24}

Only animate the elements that need animating. This is fairly obvious but can become a real bottleneck especially when dealing with large datasets. Test an elements previous position to determine whether it needs to be included in the sequence.

Depending on your interactivity you may need to set useVirtualLayout to false. Because virtualisation uses an estimate of elements displayed on screen for positioning and sizing, I found that with scrolling and dragging elements beyond the containers current scroll index, these elements were not being resolved. By setting it to false all elements are created and positioned allowing any calculations needed by those not currently displayed on the UI to still be allowed.

You can view and example of the layout here.

You can read more about the Spark SkinnableDataContainers here

Here is a nice article on creating custom layouts with Spark here

TweetBacks
Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
BlogCFC was created by Raymond Camden. This blog is running version 5.9.6.004. Contact Blog Owner