OffsetAnimator: Android animation driven by moving your finger
Today, when the competition among applications is high, an attractive design is not enough. Various features, attractive and involving interactions are needed. In one of my projects, after some attempts, designers came to a rather interesting and interactive version of the intro:
And the question of how to realize this creation came up. We considered several options:
- gif animation;
- drawable animation;
- android property animation.
GIF animation is not suitable due to its heaviness, low quality and poor rate of playback. The same can be said about drawable animation. Android property animation seemed to be a worthy but the most time consuming option. We used it for the first version of the animation, but later it became obvious that we hadn’t fully materialized the original idea: the lack of the planned interactivity, pages were switched and animated, but it was more like a movie where everything happens by itself.
It was necessary to clearly tie, associate the animation to the movement of a finger across the screen. PagerTransformer also did not fit here for a number of reasons: it lacked flexibility in implementation.
Having searched and not found suitable solutions on the Internet (now they already exist), I had to write my own creation.
So here is OffsetAnimator. A small library that allows you to play animations that depend on the movement of your finger.
Here’s how to use the library to create the animation shown above.
First, we create an activity with ViewPager and PagerAdapter:
Our animation contains graphic objects which we represent as android.View. All animation will be set on a separate custom ViewGroup which we will call AnimatorScene. Also we will need screenDimensions:
Here is the xml markup of our scene. I use either ImageView or simple FrameLayout to display:
Here is the layout of MainActivity. ViewPager is located above the AnimatorScene to handle the touch correctly:
It’s time for the most interesting part — writing our script!
To do that, we need to instantiate Scene by passing the root view and callback of our script as arguments.
The scene contains pages that are divided into steps — units of animation. Each step represents a certain animation.
Before we start the script, we need to arrange our actors in their places:
Lights, camera, action!
First of all, fish are coming swimming and the ocean is rising.
To make the animation work when it is needed, we need to determine its position in our scenario:
The initial and final values of the parameter are passed to createAnimation method. It can be any property of the view, not only coordinates.
To raise the ocean upwards, we take its available coordinate along the Y axis and subtract (the value of Y is zero at the top of the screen) some value in pixels. Before doing that, do not forget to convert dp into pixels.
The distance of one page is taken for 1f, thus, to make our animation lasting for 80% of the time, we set the following:
createAnimation (x1, x2) method has OffsetAnimator under the hood. In order to apply the calculated value to our view, the listener must be specified.
The fish on the left should not appear immediately, but a little bit later, so they are delayed:
They also arrive faster than the first animation frame ends. That’s why a smaller “distance” is specified:
So, the first (or zero to be precise) “page” is ready:
Page 2. The submarine is abruptly bouncing into the scene. For greater dynamics, this step is done using the SpringInterpolator built-in into the library:
Page 3. There is some daredevil at the wheel! The submarine is making a “dead loop”. Here, ArcAnimator is coming into the play. The view, the coordinate of the origin and the coordinate of the end, the angle and side of the turn are communicated to the factory method. Note that ArcAnimator does not require the listener to be specified, but changes the coordinates of the view implicitly.
To specify the spin-related rotation, we use the rotation in 4 key steps:
Page 4. The fish are swimming away, and the submarine is being shown close-up. To increase the size of the submarine and reduce the ones of the fish, we use the scale parameter:
The final step is to use a special adapter to associate the scene with ViewPager:
That’s it! Our animation is ready!