Skip to main content

Create Moving Experiences with Animated Transitions

October 23, 2007

{cs.r.title}







Author's note and shameless plug: Animated Transitions, the
general topic and the utility library, is explained in far more
detail in Chapter 18 of the book "http://filthyrichclients.org">Filthy Rich Clients. It seemed
too much to ask to get everyone to buy the book just to see what
this library was about, so this article was written to give an
overview and introduction to the topic. If you like what you see,
you should definitely check out the "http://filthyrichclients.dev.java.net">project on java.net to
see the code, the demos of Animated Transitions on the "http://filthyrichclients.org">book's website, and maybe even
the book itself for a more detailed explanation.

A typical application has several states that it moves between
during its lifetime: data entry forms, results screens, photo
albums with different views of the images, shopping carts with
items that you can't afford, and so on. Usually, applications do a
horrible job of moving the user between these different screens:
forms are erased before different forms take their place, results
are popped suddenly onto the screen, and graphics and GUI objects
jump discontinuously between screens. In general, each current UI
screen is taken down when it's completed and then the new screen is
displayed in its place.

HTML applications are great examples of this: you fill out some
data on one page, click the Submit button, watch it erase, and then
wait for it to paint a completely new UI. Then you spend some time
puzzling out the new interface, figuring out what you need to do,
and where the new Submit button is.

Wouldn't it be nice if applications created a more logical flow
between these different application states, to gently bring the
user with them into each new UI? What if users didn't have to
figure out each new UI from scratch, but instead were brought along
with the application so that they understood how they got
here from back there?

That's what Animated Transitions are all about:
animating the user interface from one screen of the application to
the next, to create a seamless flow between these states.
Transitions help keep the user connected to the program by helping
them understand how the UIs fit together.

The problem, of course, is that it means more work for the
developer. Having the application erase one screen and display the
next one is the most straightforward way to handle the situation.
Running some kind of animation between the screens would usually
entail actually understanding animation and then writing a pile of
custom code to animate the elements on the screens.

That's why the "http://animatedtransitions.dev.java.net/">Animated Transitions
library was written: it radically simplifies the process of
animating between application states, performs reasonable default
animations, and lets you concentrate on writing the application
code, not the animation code.

Demo Time

Let's look at a simple demo application,
FieldsOfText. This application mimics common
functionality that you may have seen elsewhere, where the user can
ask for the GUI to expand itself and provide more text fields. For
example, I use a dialog box much like this when uploading "http://weblogs.java.net/blog/chet/images/DayAtTheBeachSm.png">critically
important cartoons
to "http://weblogs.java.net/blog/chet/">my java.net blog. The
application starts with one text field, but clicking on the More
or Less buttons will increase or decrease the number of text
fields displayed.

There is also a Submit button at the bottom because, well,
because there's usually a Submit button in this type of
application. The button doesn't actually do anything here, but it
is there, like the other UI elements, to show off aspects of
animated transitions.

Here is the code that displays the GUI:

// Add the More/Less buttons container
add(moreOrLess);
// Next, add the proper number of text fields
for (int i = 0; i < numFields; ++i) {
    add(textFields[i]);
}
// Finally, add the Submit button at the bottom
add(submitPanel);

In this code, the moreOrLess component is a panel
that holds the More and Less buttons. The textFields[]
array holds the various text fields that are going to populate the
GUI, and numFields is the number that we want to
display at this time. The submitPanel component is a
panel that holds the Submit button.

Here's the basic UI that the user is first presented with:

<br "Initial screen of application" />
Figure 1. Initial screen of application

When the user clicks on the More button, a text field will be
added below the existing one, resulting in the following
screen:

<br "Second screen of application, after user clicks More button" />

Figure 2. Second screen of application, after user clicks the More
button

When the user clicks on the Less button, the last text field
goes away and the UI looks like it did in Figure 1.

In a typical application, the window might erase in between
these steps and then display the new UI. The Animated Transitions
library instead moves smoothly between these states. It fades in or
out components that are appearing or disappearing (e.g., a text
field) and moves components that are in different positions (e.g.,
the Submit button). For example, Figure 2 shows what the UI looks
like while the transition between the first and second screens is
taking place:

<br "Animated transition between the first and second screens" />
Figure 3. Animated transition between the first and second
screens

In Figure 3, we can see that the second text field is fading
into view while the Submit button is moving down.

If you'd really like to see the effect in action, I've created a
short movie clip ( "http://download.java.net/javadesktop/filthyrichclients/animtrans.mov">QuickTime
or "http://download.java.net/javadesktop/filthyrichclients/animtrans.mp4">
MPEG-4
) showing the transition effect.

Now, let's see how the demo application achieves this transition
effect.

Animated Transitions: The API

At its most basic level, the library consists of a
ScreenTransition object, which is responsible for
setting up and running the animation, and a
TransitionTarget interface, which your code needs to
implement.

ScreenTransition

This object will be created by your code with parameters that
set up the animation. The constructor looks like this:


public void ScreenTransition(JComponent transitionContainer, 
                             TransitionTarget target, 
                             Animator animator)

where:

  • transitionContainer is the container whose
    children will be animated during the transition.
  • target is an implementation of
    TransitionTarget that defines the method
    setupNextScreen(), where the GUI for the screen to be
    transitioned to is defined.
  • animator defines the parameters of the actual
    animation, such as the duration. A full description of
    Animator is beyond the scope of this article. Check
    out the Timing Framework reference in the "#resources">Resources section below for more information.

To actually run the transition at any time from your
application, you call the start() method:

public void start()

When this method is called, ScreenTransition will
set up what it needs to in order to run the transition, and will
then run the animation.

TransitionTarget
TransitionTarget is a simple interface consisting
of just one method:

public void setupNextScreen()

Your code needs to implement this method and set up the GUI of
the transition container such that when the method is done, your
application is in the state that you want it to be when the
transition is complete.

API Usage

Let's see how this API is used by the FieldsOfText
application.

First, we set up the Animator to run our transition
animations for a half-second. We will also add some acceleration
and deceleration at the beginning and end of the transition. This
acceleration/deceleration behavior is not necessary, but non-linear
movement makes for much better animations in general (as explained
in the article " "http://java.net/pub/a/today/2006/02/23/smooth-moves-solutions.html">
Smooth Moves
").

Animator animator = new Animator(500);
animator.setAcceleration(.2f); 
animator.setDeceleration(.2f);

We then set up the ScreenTransition object to use
our main JComponent object as a container for the
transition, that same object as the TransitionTarget
where setupNextScreen() is implemented, and the
animator that we set up earlier:

ScreenTransition transition = 
        new ScreenTransition(this, this, animator);

We trigger the transition when the user clicks either the More
or Less button in the actionPerformed() method:

public void actionPerformed(ActionEvent ae) {
    boolean changed = false;
    if (ae.getSource().equals(moreButton)) {
        if (numFields &lt; MAX_FIELDS) {
            numFields++;
            changed = true;
        }
    } else if (ae.getSource().equals(lessButton)) {
        if (numFields &gt; 1) {
            numFields--;
            changed = true;
        }
    }
    if (changed) {
        transition.start();
    }
}

Finally, we handle the callback from
ScreenTransition into our code in the
setupNextScreen() method:

public void setupNextScreen() {
    // First, clear out the previous GUI and start from scratch
    removeAll();
    
    // Add the More/Less buttons
    add(moreOrLess);
    // Next, add the proper number of text fields
    for (int i = 0; i &lt; numFields; ++i) {
        add(textFields[i]);
    }
    // Finally, add the Submit button at the bottom
    add(submit);
}

Note that this is nearly the same code that we showed earlier
when we described our GUI setup code; the only addition is that we
first clear out the previous GUI with the call to
removeAll(); otherwise, all that this method does is
set up the GUI for the appropriate screen of the application.

And that's it! There is more code in the application to
handle things like setting up the JFrame, drawing that
cool blue gradient in the background, and setting up some details
about the components and layout management, but most of the real
logic of the application, particularly all of the code concerned
with animated transitions, is listed above.

So how does it actually work?

How It Works

When your code calls the start() method,
ScreenTransition figures out the current attributes of
the components in the transition container, such as their position
and size. It then calls your setupNextScreen() method,
where you set up the GUI for the next screen. Finally, it figures
out the attributes for the components in this next screen that you
have set up.

Note that the system expects the transition container to share
components when appropriate, not to have completely different
components representing the same things. So, for example, if there
is a Submit button in the previous screen and a Submit button in
the next screen, you probably want to use the same actual
JButton object in both cases to get the desired
effect. Otherwise, the system will think that the previous button
is going away and a new button is coming into being. There's no
magic here; if you intend for components to be shared between
screens, then you should use the same actual components in the
screens.

At this point, ScreenTransition has information on
all of the components in both screens: which ones are in which
screen, where they are, and how big they are. So it can figure out
what changes will occur to each of these components between the two
screens. Any component that changes between screens will undergo
one of the following three transition types:

  • Appearing: The component is not in the first screen but is in
    the second.
  • Disappearing: The component is in the first screen but not in
    the second.
  • Changing: The component is in both screens, but changes between
    the screens.
ScreenTransition will then pick an appropriate
transition effect for each component:

  • Appearing: The component will fade in during the
    transition.
  • Disappearing: The component will fade out during the
    transition.
  • Changing: The component will move and scale as appropriate
    during the transition.

Once it has all of this information,
ScreenTransition will begin the animation, altering
the appearance of each component during the animation according to
the transition effect associated with that component.

When the transition is complete, control is returned back to the
application and the GUI previously set up by your application in
setupNextScreen() is live.

Custom Effects

The built-in transition effects were created to handle the
common cases that applications would generally want. Fading and
moving/resizing the components is reasonable default behavior for
typical situations. But applications that use Animated Transitions
extensively might be interested in creating custom effects for
particular components or situations. For example, maybe you want a
disappearing component to zoom in or out, or to slide off
the screen.

The transition effects used by the library were written to be
extensible so that you can plug in your own effects by creating the
effects and registering them with the system. These effects are
associated with both a component and transition type (appearing,
disappearing, or changing). When ScreenTransition
searches for an appropriate effect to use for any given component
and transition type, it will use a custom effect if one has been
registered.

Writing a custom effect can be quite easy--you override just
two or three methods to handle such functionality as setup, cleanup, and
painting during the transition. Showing how to actually write a
custom effect is beyond the scope of this brief article. But if
you're interested in this feature, check out the demos for "Chapter
18: Animated Transitions" on the "http://filthyrichclients.org">book's website, which show
custom effects in code and action.

Neat Tricks

There are various techniques used in Animated Transitions in
order to get the functionality and performance that the library
needs. A full description of these techniques is more than we have
space for here, but feel free to check out the code and the book
for more details. For example, the way that the library handles
setting up the second screen before the transition runs is
interesting. Also, the way that the library deals with arbitrary
layout managers in either or both screens is worth a look. And the
way that the library takes image snapshots of components for fast
display during the transition enables good performance while also
enabling complex animations.

Future Work

The Animated Transitions library is a work in progress. I hope
to continue refining the API and enhancing the functionality as
time and experience march on. In the meantime, the library is quite
useful at what it does and should provide developers the ability to
easily and seamlessly connect different application states and
provide a moving experience for their users.

Try it out and let me know if it moves you.

Resources


width="1" height="1" border="0" alt=" " />
Chet Haase I'm a graphics geek. I worked at Sun, Adobe, and Google, always on the UI side of things.
Related Topics >> GUI   |