Support free tutorials



vogella training Training Books

Using animations in Android application - Tutorial

Lars Vogel

Version 2.9

21.07.2015

Android Property Animation API

This tutorial describes how to use Animations in Android. The tutorial is based on Android Studio and Android 5.1.


Table of Contents

1. Android Animations
1.1. Using animations
1.2. Animator and AnimatorListener
1.3. ViewPropertyAnimator
1.4. Layout animations
1.5. Animations for Activity transition
2. Android Basics
3. Tutorial: View Animation
4. Animations for fragment transitions
5. Activity animations in Android with shared views
6. About this website
7. Links and Literature
7.1. Android Animation Resources
7.2. vogella GmbH training and consulting support

1. Android Animations

1.1. Using animations

Android 3.0 introduced the Properties Animation API which allow to change object properties over a predefined time interval.

The API allows to define for arbitrary object properties a start and end value and apply a time-based change to this attribute. This API can be applied on any Java object not only on Views.

1.2. Animator and AnimatorListener

The superclass of the animation API is the Animator class. Typically the ObjectAnimator class is used to modify the attributes of an object.

You can also add an AnimatorListener class to your Animator class. This listener is called in the different phases of the animation. You can use this listener to perform actions before or after a certain animation, e.g. add or remove a View from a ViewGroup.

1.3. ViewPropertyAnimator

The ViewPropertyAnimator class introduced in Android 3.1 provides a simpler access to typical animations which are performed on views.

The animate() method on a view returns the ViewPropertyAnimator object. This object allows to perform simultaneous animations. It has a fluent API and allows setting the duration of the animation.

The target of ViewPropertyAnimator is to provide a very simple API for typical animations.

The following code shows an example of the usage of this method.

// Using hardware layer
myView.animate().translationX(400).withLayer(); 

For performance optimization you can also let ViewPropertyAnimator use a hardware layout.

// Using hardware layer
myView.animate().translationX(400).withLayer(); 

You can also directly define a Runnable to be executed at the start and the end of the animation.

// StartAction
myView.animate().translationX(100).withStartAction(new Runnable(){
  public void run(){
    viewer.setTranslationX(100-myView.getWidth());
    // do something
  }
});

// EndAction
myView.animate().alpha(0).withStartAction(new Runnable(){
  public void run(){
    // Remove the view from the layout called parent
    parent.removeView(myView);
  }
}); 

The setInterpolator() allows to define an object of type TimeInterpolator which defines the change of the value over time. The standard is linear. The Android platform defines a few default ones as for example AccelerateDecelerateInterpolator where the rate of change starts and ends slowly but accelerates through the middle.

Via the setEvaluator method you can set an object of type TypeEvaluator which allow you to create animations on arbitrary property types, by providing custom evaluators for types that are not automatically understood and used by the animation system.

1.4. Layout animations

The LayoutTransition class allows setting animations on a layout container and a change on the view hierarchy of this container will be animated.

package com.example.android.layoutanimation;

import android.animation.LayoutTransition;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class MainActivity extends Activity {

  private ViewGroup viewGroup;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LayoutTransition l = new LayoutTransition();
    l.enableTransitionType(LayoutTransition.CHANGING);
    viewGroup = (ViewGroup) findViewById(R.id.container);
    viewGroup.setLayoutTransition(l);

  }

  public void onClick(View view) {
    viewGroup.addView(new Button(this));
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
  }
} 

1.5. Animations for Activity transition

Animations can be applied to Views but it is also possible to apply them on the transition between activities.

The ActivityOptions class allows defining defaults or customer animations.

public void onClick(View view) {
  Intent intent = new Intent(this, SecondActivity.class);
  ActivityOptions options = ActivityOptions.makeScaleUpAnimation(view, 0,
      0, view.getWidth(), view.getHeight());
  startActivity(intent, options.toBundle());
} 

2. Android Basics

The following description assumes that you have already basic knowledge in Android development.

Please check the Android development tutorial to learn the basics. Also see Android development tutorials for more information about Android development.

3. Tutorial: View Animation

This tutorial demonstrates the usage of the Properties animation API.

Create a new Android project called com.vogella.android.animation.views with the activity called AnimationExampleActivity. The layout file should be called main.xml. Change this file to the following code.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/Button01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="startAnimation"
            android:text="Rotate" />

        <Button
            android:id="@+id/Button04"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="startAnimation"
            android:text="Group" >
        </Button>

        <Button
            android:id="@+id/Button03"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="startAnimation"
            android:text="Fade" />

        <Button
            android:id="@+id/Button02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="startAnimation"
            android:text="Animate" />

    </LinearLayout>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:src="@drawable/icon" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/imageView1"
        android:layout_alignRight="@+id/imageView1"
        android:layout_marginBottom="30dp"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout> 

Create the following menu resource.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/item1"
        android:showAsAction="ifRoom"
        android:title="Game">
    </item>

</menu> 

Change your activity to the following.

package com.vogella.android.animation.views;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class AnimationExampleActivity extends Activity {

  
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void startAnimation(View view) { float dest = 0; ImageView aniView = (ImageView) findViewById(R.id.imageView1); switch (view.getId()) { case R.id.Button01: dest = 360; if (aniView.getRotation() == 360) { System.out.println(aniView.getAlpha()); dest = 0; } ObjectAnimator animation1 = ObjectAnimator.ofFloat(aniView, "rotation", dest); animation1.setDuration(2000); animation1.start(); // Show how to load an animation from XML // Animation animation1 = AnimationUtils.loadAnimation(this, // R.anim.myanimation); // animation1.setAnimationListener(this); // animatedView1.startAnimation(animation1); break; case R.id.Button02: // shows how to define a animation via code // also use an Interpolator (BounceInterpolator) Paint paint = new Paint(); TextView aniTextView = (TextView) findViewById(R.id.textView1); float measureTextCenter = paint.measureText(aniTextView.getText() .toString()); dest = 0 - measureTextCenter; if (aniTextView.getX() < 0) { dest = 0; } ObjectAnimator animation2 = ObjectAnimator.ofFloat(aniTextView, "x", dest); animation2.setDuration(2000); animation2.start(); break; case R.id.Button03: // demonstrate fading and adding an AnimationListener dest = 1; if (aniView.getAlpha() > 0) { dest = 0; } ObjectAnimator animation3 = ObjectAnimator.ofFloat(aniView, "alpha", dest); animation3.setDuration(2000); animation3.start(); break; case R.id.Button04: ObjectAnimator fadeOut = ObjectAnimator.ofFloat(aniView, "alpha", 0f); fadeOut.setDuration(2000); ObjectAnimator mover = ObjectAnimator.ofFloat(aniView, "translationX", -500f, 0f); mover.setDuration(2000); ObjectAnimator fadeIn = ObjectAnimator.ofFloat(aniView, "alpha", 0f, 1f); fadeIn.setDuration(2000); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(mover).with(fadeIn).after(fadeOut); animatorSet.start(); break; default: break; } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.mymenu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent = new Intent(this, HitActivity.class); startActivity(intent); return true; } }

Create a new activity called HitActivity.

package com.vogella.android.animation.views;

import java.util.Random;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class HitActivity extends Activity {
  private ObjectAnimator animation1;
  private ObjectAnimator animation2;
  private Button button;
  private Random randon;
  private int width;
  private int height;
  private AnimatorSet set;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.target);
    width = getWindowManager().getDefaultDisplay().getWidth();
    height = getWindowManager().getDefaultDisplay().getHeight();
    randon = new Random();

    set = createAnimation();
    set.start();
    set.addListener(new AnimatorListenerAdapter() {

      @Override
      public void onAnimationEnd(Animator animation) {
        int nextX = randon.nextInt(width);
        int nextY = randon.nextInt(height);
        animation1 = ObjectAnimator.ofFloat(button, "x", button.getX(),
            nextX);
        animation1.setDuration(1400);
        animation2 = ObjectAnimator.ofFloat(button, "y", button.getY(),
            nextY);
        animation2.setDuration(1400);
        set.playTogether(animation1, animation2);
        set.start();
      }
    });
  }

  public void onClick(View view) {
    String string = button.getText().toString();
    int hitTarget = Integer.valueOf(string) + 1;
    button.setText(String.valueOf(hitTarget));
  }

  private AnimatorSet createAnimation() {
    int nextX = randon.nextInt(width);
    int nextY = randon.nextInt(height);
    button = (Button) findViewById(R.id.button1);
    animation1 = ObjectAnimator.ofFloat(button, "x", nextX);
    animation1.setDuration(1400);
    animation2 = ObjectAnimator.ofFloat(button, "y", nextY);
    animation2.setDuration(1400);
    AnimatorSet set = new AnimatorSet();
    set.playTogether(animation1, animation2);
    return set;
  }
} 

If you run this example and press the different Buttons, the animation should start. Via the ActionBar you can navigate to your other activity.

4. Animations for fragment transitions

During a fragment transaction you can define animations which should be used based on the Property Animation API via the setCustomAnimations() method.

You can also use several standard animations provided by Android via the setTransition() method call. These are defined via the constants starting with FragmentTransaction.TRANSIT_FRAGMENT_*.

Both methods allow you to define an entry animation and an existing animation.

5. Activity animations in Android with shared views

Android 5.0 adds the capability to animate between activities and to have shared views between these activity. If you define a shared part the old view with be animating into the position and size of the new view.

To test this create a project with the top level package called com.vogella.android.activityanimationwithsharedviews.

Create two activity with two different layout, both containing a ImageView with the same android:transitionName property.

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/sharedimage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_sharedimage"
        />

</LinearLayout> 

activity_second.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.vogella.android.activityanimationwithsharedviews.SecondActivity">

    <ImageView
        android:id="@+id/sharedimage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_sharedimage"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        android:id="@+id/textView" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button"
        android:transitionName="sharedImage"
        android:layout_below="@+id/textView"
        android:layout_alignParentStart="true"
        android:layout_marginTop="54dp" />

</RelativeLayout> 

Adjust your activity code.

package com.vogella.android.activityanimationwithsharedviews;

import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ImageView sharedImage = (ImageView) findViewById(R.id.sharedimage);
        sharedImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //This is where the magic happens. 
              // makeSceneTransitionAnimation takes a context, view,
              // a name for the target view.
                ActivityOptions options = 
                    ActivityOptions.
                    makeSceneTransitionAnimation(MainActivity.this, sharedImage, "sharedImage");
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent, options.toBundle());
            }
        });

    }

} 

package com.vogella.android.activityanimationwithsharedviews;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }
} 

If you run your application and click on the image view, it is animated to the view with the same android:transitionName property, in our case the button.

6. About this website

7. Links and Literature

7.2. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT
The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”. The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.