Skip to main content
Known Participant
August 27, 2009
Question

Core IAnimator in Spark

  • August 27, 2009
  • 1 reply
  • 954 views

Man, it's very difficult to customize the animation system in spark.  I realize that a lot of effort is going into it, but why not take a look at how simple and powerful openflux solved the problem?

For instance, in Spark, mixed into the core of the ScrollBar and the Slider are "private" variables for an "Animation" object that controls animating scrolling.  Hardcore...  There are a few things difficult about this approach:

1) You don't have access to that animator, other than through hard-coded instance methods that, if that philosophy were applied everywhere in Flex would get totally unmanageable.

2) There is no consistency in the design in which these animators are used, no interface, it's almost like they're just there to solve some super specific case, but good luck trying to solve the next.

3) It's built into the scrollbar, like the Scrollbar was built into the Flex 3 Container, and that wasn't the best idea.  A "ScrollBar" doesn't by nature need an animator that animates its scrolling.  That's an add-on.

If the UIComponent just had an IAnimator property that stored an object that could animate anything (or "play" "Animation" instances), that would be much more flexible.  And I could use TweenMax or Tweener if I'd like, or Away3D's animation stuff using Flex's IAnimator interface.

In addition, this would make it extremely easy to animate layout properties, and animate between layouts (from Vertical to Horizontal for instance).  To wire that up right now would be tough:  I'd have to create my own Vertical and Horizontal Layouts and implement this whole system, or hack together something that would be hard to reuse or customize.  All you'd need to do is add a controller to a component that grabbed a layoutElement position token and ran it through the animator, and the animator could do the fancy matrix/layout bound stuff.

I don't see why that's an issue.  If someone has a reason why they don't want to do this, please let me know, because from my experience it's been a wonderful tool and makes development exciting and much easier.

Best,

Lance

This topic has been closed for replies.

1 reply

Participant
August 27, 2009

Hey Lance,

The reason the animation functionality is buried in ScrollBar is that, in a tight release where there was already enough to do, it was a choice between not having animated behavior at all or having it in such a way that we didn't paint ourselves into a corner API-wise. I would like something much more exposed, extensible, and general there, but I would rather have some good behavior for the standard components than miss the chance to do anything because we couldn't fit it in. Also, note that any feature like this that includes API necessarily takes a lot more time and thought, because those are the decisions we have to live with forever. As it is, we are now free to go back in there in a future release and implement a more general system for which we do expose hooks, having thought them through enough to be happy with them.

As for your suggestion about adding an IAnimator property to UIComponent, I confess I don't follow. You already have the ability to target an animation at arbitrary properties of any component. What would you get out of having an animation object in a component? And what would that animation object do? Maybe you could post a snippet of what code you'd like to write, or describe more fully the use case you're trying to make work.

As for making layout animate nicely, I think there's a bit more to it than this. You can do it in specific circumstances, when you know exactly what's going on (which is easier at the app level). Animating layout in general is a bit trickier (having tried a bit of it myself in this release, and having backed off realizing that I wasn't going to reach a Happy Place with it). But again, I don't understand how we get from having some IAnimator object on UIComponent to being able to animate layout properties.

Chet.

viatroposAuthor
Known Participant
August 27, 2009

Thanks for the great reply Chet.

Makes a lot of sense about wanting to get something out there, I know what it's like to try to take on too grand a task at once.

The question of whether or not there should be an 'animator' property applies to a lot more than just that.  It's definitely arguable that the UIComponent doesn't need an IAnimator built in, but then again it doesn't need a 'tooltip', 'errorString', 'cursorManager', or 'repeater' either.  Those would be attached to components through controllers, IAttachables, or something.  That's somewhat how the effects work.

I would put the 'animator' into the UIComponent just for simplicity, so you don't have to import it every time you want to use it, and so it doesn't have to be a manager.  Plus it now has a direct "target" it is attached to.  If it were like the effect, and you wanted every component to be animated, you would either have to create a ton of IAnimator objects manually, or do some tricky 'findById" business in your document if you wanted to abstract it away.

My only thing is I can easily animate state changes in the skin, and changes in/between layouts, using a simple Animator that's built into the Container/Group that the layout has access too.  Here's how I did the layouts (off the top of my head):

VerticalLayout:

// keeps calculations very formal

public function getToken(child:IVisualElement, index:int):Object

{

     var token:Object = {};

     ... calculate x and y like normal, but just for the current index (we're basically in the for-loop now

     token.x = x;

     token.y = y;

     ...

     return token;

}

public function updateDisplayList():void

{

     for (i; i < numElements; i++)

     {

          var child:IVisualElement = layoutElements;

          var token:Object = getToken(child, i);

          if (target.animator)

               target.animator.animate(child, token);

          else

               child.setLayoutBoundsPosition(token.x, token.y);

     }

}

... It would be even easier for developers if they just passed in the animation token (could be a typed object) and the child into the IAnimator, and it figured out if we wanted to animate it (from CSS or wherever), and if not, just did the "setLayoutBounds..." stuff.  That's how I'm doing it now.  Once I translate the VerticalLayout and HorizontalLayout into it I'll post it up, I'm working on the Coverflow now.

But basically, this is the API I'm using for layouts (only showing the 'updateDisplayList' part now).  I don't have to customize this in subclasses:

public function updateDisplayList():void

{

     for (i; i < numElements; i++)

     {

          var child:IVisualElement = layoutElements;

          var token:Object = getToken(child, i);

          if (layoutModifier != null)

               layoutModifier(token, child, i); // function so you can customize layout variables just before they are set.

          animator.animate(child, token);

     }

}

Then the developer just implements the "getToken(child, index)" method, keeping it simple, and giving you access to the token if you wanted to customize it in your MXML view.  To make a StepLayout from the VerticalLayout following this pattern, you'd just do something like this:

<spark:VerticalLayout layoutModifier="makeItStep"/>

public function makeItStep(token:Object, child:IVisualElement, index:int):void

{

     token.x = token.x * i;

}

.. or into an arc, you'd just do some trigonometry stuff, and you could add all kinds of state logic, animation between layouts, etc., without ever copy-pasting code or extending core layout classes, which are not easy to make.

I would love to try out maybe making it a manager or something, but that just makes it so the manager has to keep track of a billion things, and I have to import that everywhere I want to use it (which is everywhere).  I don't really like the idea of making it like the effects, where you have to have 50 lines of MXML just to make a ball bounce, or a button to do some interesting stuff with key frames.  Or to animate skins with tons of fills and gradients, it would get crazy.  That can be solved like this:

protected function stateChangeHandler(event:StateChangeEvent):void

{

     if (event.newState != event.oldState)

     {

          for (i; i < numElements; i++)

          {

               var child:IVisualElement = skin.layoutElements;

               var token:Object = getToken(child, i);

               animator.animate(child, token);

          }

     }

}

And that token can either be an IEffect, or something used by TweenMax, Tweener, etc, and the animator will figure out how to "play" or run that.

Having it part of the UIComponent would just make it so we didn't have to think about how to animate things, it would just "work".  Otherwise it's a little more complicated, that's probably why not many people use really designer effects/animations with Flex right now.

Best,
Lance