fbpx

Using Transitions API to Create Android App Animations

Sergey Grigoriev

Sergey Grigoriev

IT copywriter

#Mobile

21 May 2015

Reading time:

21 May 2015

Creating Android app animations

Despite the high demand and prevalence of animation in mobile apps, developers point out that the process of creating animation for Android OS has always been a challenge. While iOS has long provided useful tools for working with animation, solutions for Android that help optimize developers’ work are relatively new.

But surely these animation tools have greatly simplified the lives of programmers. Such tools are convenient for creating a variety of app animations. Instead of animating individual screens, developers can animate the so-called Scenes, while transitions are generated automatically by activity recognition transition API. And that’s only the tip of the possibilities iceberg! The information I’m going to share here will definitely be useful to anyone developing apps for the world’s most popular mobile OS.

Transitions API: How does it work?

Even in Android 4.0, there was an early solution to the Android app animations problem: the flag animateLayoutChange for ViewGroup. However, this tool was not flexible enough and could not provide developers with complete control over the transitions. But starting Android 4.4 KitKat and beyond, Transitions API has been implemented. Transitions API also exists in support library, so it can be used to create animation for almost any device with Android OS.

In KitKat Transition API, concepts such as Scene and Transition between scenes appear. In order to determine the root layout, Scene root was introduced. All changes in the scenes happen inside the Scene root. At the same time, the Scene itself is essentially a wrapper over the ViewGroup, describing its own status and all the statuses of the View objects. Transition is a mechanism that allows reading View parameters, which change between the Scenes and generate animations to make the changes smooth.

Transition Frameworks in KitKat Transition API provides the following features to create animations:

  • Group-level animations: the ability to animate the whole hierarchy of View objects. Developer points ViewGroup and animations automatically apply to each of its elements
  • Transition-based animation
  • Built-in animations: simple animations such as dissolution, darkening, resizing, movement, etc.
  • Resource file support: developers can create animations from resource files without writing code
  • Lifecycle callbacks: provides all the necessary methods of control over the playback

Despite all of its advantages, this new method also has some limitations:

  • It may falter if applied to the most complex SurfaceView or TextureView, which do not work in UI thread
  • AdapterView, such as ListView, when you have to animate individual elements from the list
  • Occasionally, there are problems with synchronization when you try to resize a TextView: the font may be displayed in the next scene before the changing of other objects is finished

However, these restrictions aren’t very significant. In practice, situations when you might need to apply an animation to SurfaceView, for instance, are extremely rare.

Consider the below examples of animation in Transition Frameworks:

Creating Scene from Resource file:

res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/master_layout"> 
 <TextView 
 android:id="@+id/title" 
 ... 
 android:text="Title"/> 
 <FrameLayout 
 android:id="@+id/scene_root"> 
 <include layout="@layout/scene_first" /> 
 </FrameLayout> 
</LinearLayout>

res/layout/scene_first.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/scene_container" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" > 
 <TextView 
 android:id="@+id/text_view1 
 android:text="Text Line 1" /> 
 <TextView 
 android:id="@+id/text_view2 
 android:text="Text Line 2" /> 
</RelativeLayout>

res/layout/scene_second.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/scene_container" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" > 
 <TextView 
 android:id="@+id/text_view2 
 android:text="Text Line 2" /> 
 <TextView 
 android:id="@+id/text_view1 
 android:text="Text Line 1" /> 
</RelativeLayout>
Scene mFirstScene; 
Scene mSecondScene; 
 
// Create the scene root for the scenes in this app 
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root); 
 
// Create the scenes 
mFirstScene = 
 Scene.getSceneForLayout(mSceneRoot, R.layout.scene_first, this); 
mSecondScene = 
 Scene.getSceneForLayout(mSceneRoot, R.layout.scene_second, this);

Creating Scene from Code:

// Obtain the scene root element 
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root); 
 
// Obtain the view hierarchy to add as a child of 
// the scene root when this scene is entered 
mViewHierarchy = (ViewGroup)findViewById(R.id.scene_conteiner); 
 
// Create a scene 
Scene scene = new Scene(mSceneRoot, mViewHierarchy);\

Creating Transitions from Resource file:

res/transition/fade_transition.xml

<fade xmlns:android="http://schemas.android.com/apk/res/android" /> 
 
Transition mFadeTransition = 
 TransitionInflater.from(this). 
 inflateTransition(R.transition.fade_transition);

And also from code:

Transition mFadeTransition = new Fade();

You can create entire animation sets. For example: move, resize, and darken your object simultaneously:

In resource:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" 
 android:transitionOrdering="sequential"> 
 <fade android:fadingMode="fade_out" /> 
 <changeBounds /> 
 <fade android:fadingMode="fade_in" /> 
</transitionSet>

In code:

TransitionSet set = new TransitionSet(); 
set.addTransition(new Fade()) 
 .addTransition(new ChangeBounds()) 
 .addTransition(new AutoTransition());

Apply the animation to a certain View object, not the whole Scene, if you need:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> 
 <changeBounds /> 
 <fade android:fadingMode="fade_in" /> 
 <targets> 
 <target android:targetId="@id/transition_title" /> 
 </targets> 
 </fade> 
</transitionSet>

Transition Manager is created by a single line of code. It is needed to write all the Scenes and Transitions in one place. Transition Manager allows to speed up the work and control all animations more effectively.

res/transition/transition_manager.xml

<transitionManager xmlns:app="http://schemas.android.com/apk/res-auto"> 
 <transition 
 app:fromScene="@layout/scene_reg1" 
 app:toScene="@layout/scene_reg2" 
 app:transition="@transition/trans_reg1_to_reg2" /> 
 <transition 
 app:fromScene="@layout/scene_reg2" 
 app:toScene="@layout/scene_reg3" 
 app:transition="@transition/trans_reg2_to_reg3" /> 
 ... 
</transitionManager>
TransitionManager transitionManager = TransitionInflater.from(context) 
 .inflateTransitionManager(R.transition.transition_manager, sceneRoot);

How to run Scenes? Easy!

With custom Transitions:

mTransitionManager.transitionTo(scene);

or

TransitionManager.go(scene, fadeTransition);

With default Transitions:

TransitionManager.go(scene);

Or even without Transitions:

scene.enter();

You can also use Transitions without creating Scenes:

res/layout/activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/mainLayout" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" > 
 <EditText 
 android:id="@+id/inputText" 
 android:layout_alignParentLeft="true" 
 android:layout_alignParentTop="true" 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" /> 
 ... 
</RelativeLayout>

MainActivity.java

private TextView mLabelText; 
private Fade mFade; 
private ViewGroup mRootView; 
 
// Load the layout 
setContentView(R.layout.activity_main); 
 
// Create a new TextView and set some View properties 
mLabelText = new TextView(); 
mLabelText.setText("Label").setId("1"); 
 
// Get the root view and create a transition 
mRootView = (ViewGroup) findViewById(R.id.mainLayout); 
mFade = new Fade(IN); 
 
// Start recording changes to the view hierarchy 
TransitionManager.beginDelayedTransition(mRootView, mFade); 
 
// Add the new TextView to the view hierarchy 
mRootView.addView(mLabelText); 
 
// When the system redraws the screen to show this update, 
// the framework will animate the addition as a fade in

Using the intuitive interface of TransitionListener, you can control the playback of each animation element:

public static interface TransitionListener { 
 void onTransitionStart(Transition transition); 
 
 void onTransitionEnd(Transition transition); 
 
 void onTransitionCancel(Transition transition); 
 
 void onTransitionPause(Transition transition); 
 
 void onTransitionResume(Transition transition); 
}

Create your own animation. For example, you can change background color of the View object:

public class ChangeColor extends Transition { 
 
 private static final String PROPNAME_BACKGROUND = 
"customtransition:change_color:background"; 
 
 private void captureValues(TransitionValues values) { 
 values.values.put(PROPNAME_BACKGROUND, values.view.getBackground()); 
 } 
 
 @Override 
 public void captureStartValues(TransitionValues transitionValues) { 
 captureValues(transitionValues); 
 } 
 
 @Override 
 public void captureEndValues(TransitionValues transitionValues) { 
 captureValues(transitionValues); 
 } 
 
 @Override 
 public Animator createAnimator(ViewGroup sceneRoot, 
 TransitionValues startValues, 
 TransitionValues endValues) { 
 if (null == startValues || null == endValues) { 
 return null; 
 } 
 
 final View view = endValues.view; 
 
 Drawable startBackground = 
 (Drawable) startValues.values.get(PROPNAME_BACKGROUND); 
 Drawable endBackground = 
 (Drawable) endValues.values.get(PROPNAME_BACKGROUND); 
 
 ColorDrawable startColor = (ColorDrawable) startBackground; 
 ColorDrawable endColor = (ColorDrawable) endBackground; 
 
 if (startColor.getColor() == endColor.getColor()) { 
 return null; 
 } 
 
 ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), 
 startColor.getColor(), endColor.getColor()); 
 animator 
 .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
 @Override 
 public void onAnimationUpdate(ValueAnimator animation) { 
 Object value = animation.getAnimatedValue(); 
 if (null != value) { 
 view.setBackgroundColor((Integer) value); 
 } 
 } 
 }); 
 return animator; 
 } 
 
}

Intermediate values are generated automatically, that’s why in our example the color gradually changes from red to blue. This method opens up opportunities to create a variety of custom animations and transitions: imagination of developers is limited only to the requirements of a particular project.

Why should you care?

Fast speed and simplicity of the process of creating animations adds drive to the development of mobile apps. Azoft team is very enthusiastic about the Transitions API and we are already using this method in our projects. The ability to create animations using Scenes, saving time and effort, has been helpful to both our developers and clients, who can get the results faster.

Tell us about your experience in Android app animations. Do you use Transitions API? What are this method’s pros and cons? What other tools do you use to create animation for mobile apps?

Comments

Filter by

close

TECHNOLOGIES

INDUSTRIES