1. Les animations sous Android

1-1. Aperçu

Android 3.0 a introduit l'API Property Animation qui permet de modifier les propriétés des objets sur un intervalle de temps prédéfini.

L'API permet de définir des valeurs de début et de fin de ces propriétés et d'opérer une modification temporelle sur les attributs. Cette API peut être appliquée à n'importe quel objet Java et non aux seules View.

1-2. Les classes Animator et AnimatorListener

La superclasse de l'API d'animation est la classe Animator. Typiquement, la classe ObjectAnimator est utilisée pour modifier les attributs d'un objet.

Vous pouvez également ajouter à votre classe Animator une classe AnimatorListener. Cet écouteur est appelé dans les différentes phases de l'animation. Vous pouvez l'utiliser pour effectuer des actions avant ou après une animation, par exemple ajouter ou supprimer une vue d'un ViewGroup.

1-3. La classe ViewPropertyAnimator

La classe ViewPropertyAnimator introduite dans Android 3.1 offre un accès plus simple aux animations typiques effectuées sur des vues.

Dans une vue, la méthode animate() retourne l'objet ViewPropertyAnimator. Celui-ci permet de réaliser des animations simultanées. Il dispose d'une API fluide et permet de définir la durée de l'animation.

L'objectif de ViewPropertyAnimator est de fournir une API très simple pour animations types.

Le code suivant montre un exemple d'utilisation de cette méthode.

 
Sélectionnez
// Utiliser la couche matérielle
myView.animate().translationX(400).withLayer();

Pour optimiser les performances, vous pouvez aussi laisser ViewPropertyAnimator utiliser une disposition matérielle.

 
Sélectionnez
// Utiliser la couche matérielle
myView.animate().translationX(400).withLayer();

Vous pouvez également définir directement un Runnable à exécuter au début et à la fin de l'animation.

 
Sélectionnez
// DébutAction
myView.animate().translationX(100).withStartAction(new Runnable(){
    public void run(){
        viewer.setTranslationX(100-myView.getWidth());
        // faites quelque chose 
    }
});

// FinAction
myView.animate().alpha(0).withStartAction(new Runnable(){
    public void run(){
        // Remove the view from the layout called parent Supprimez la vue de la mise en page parent
        parent.removeView(myView);
    }
});

La méthode setInterpolator() permet de définir un objet de type TimeInterpolator qui détermine le changement de la valeur au fil du temps. La norme est linéaire. La plate-forme Android spécifie quelques interpolateurs par défaut, comme AccelerateDecelerateInterpolator où le taux de changement commence et se termine lentement, mais accélère au milieu.

Par la méthode setEvaluator(), vous pouvez définir un objet de type TypeEvaluator qui vous permet de créer des animations sur des types quelconques de propriétés, en fournissant des évaluateurs personnalisés pour les types qui ne sont pas automatiquement compris et utilisés par le système d'animation.

1-4. Les animations de mise en page

La classe LayoutTransition permet des animations d'adaptation sur un conteneur de mise en page et un changement dans la hiérarchie de la vue de ce conteneur sera animé.

 
Sélectionnez
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. Les animations de transition d'activité

Les animations peuvent être appliquées aux vues, mais il est également possible de les appliquer aux transitions entre activités.

La classe ActivityOptions permet de définir des animations par défaut ou personnalisées.

 
Sélectionnez
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. Prérequis

Ce qui suit suppose que vous ayiez déjà des notions de développement Android.

Veuillez consulter le tutoriel de développement Android, (tutoriel Developpez : « Tutoriel sur le développement Android ») pour en apprendre les bases. Voir aussi les tutoriels de développement Android pour plus d'informations à ce sujet.

3. Tutoriel : l'animation d'une vue

Ce tutoriel démontre l'utilisation de l'API Property Animation.

Créez un nouveau projet Android appelé com.vogella.android.animation.views avec l'activité appelée AnimationExampleActivity. Le fichier de mise en page doit s'appeler main.xml. Modifiez ce fichier comme suit.

 
Sélectionnez
<?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>

Créez la ressource menu suivante.

 
Sélectionnez
<?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>

Modifiez votre activité comme ci-dessous.

 
Sélectionnez
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 {

    /** Appelée lorsque l'activité est créée. **/
    @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();
                // Montre comment charger une animation à partir de XML
                // Animation animation1 = AnimationUtils.loadAnimation(this,
                // R.anim.myanimation);
                // animation1.setAnimationListener(this);
                // animatedView1.startAnimation(animation1);
                break;

            case R.id.Button02:
                // montre comment définir une animation par le code 
                // utilise également un interpolateur (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:
                // démontre la variation de la couleur et l'ajout d'un 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;
    }
}

Créez une nouvelle activité appelée HitActivity.

 
Sélectionnez
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;
    }
}

Si vous exécutez cet exemple et appuyez sur les différents boutons, l'animation devrait démarrer. Vous pouvez naviguer vers vos autres activitésvia l'ActionBar.

4. Les animations de transition de fragment

Pendant une transaction de fragment, vous pouvez définir des animations basées sur l'API Property Animation à l'aide de la méthode setCustomAnimations().

Vous pouvez également utiliser plusieurs animations standard fournies par Android via l'appel à la méthode setTransition(). Celles-ci sont désignées par des constantes commençant par FragmentTransaction.TRANSIT_FRAGMENT_*.

Les deux méthodes permettent de préciser une animation de début et une animation de fin.

5. L'API Property Animation pour versions d'Android plus anciennes

Jake Wharton a créé une bibliothèque qui permet d'utiliser l'API Property Animation aussi dans les versions d'Android antérieures à la 4.0.

Vous trouverez plus d'informations sur le site Web du projet : NineOldAndroids.

6. Soutenez les tutoriels gratuits vogella

Ce tutoriel est libre sous la licence CC BY-NC-SA 3.0 DE. Son code source est distribué sous la Licence publique Eclipse. Voir la page vogella License pour plus de détails sur les conditions de réutilisation.

La rédaction et la mise à jour de ces tutoriels nécessitent beaucoup de travail. Si ce service gratuit de la communauté vous a été utile, vous pouvez soutenir la cause en faisant un don, ainsi qu'en signalant les fautes de frappe et de contenu.

6-1. Merci

Si cet article vous a été utile, vous pouvez faire un don à Lars Vogel sur la page de l'article original.

6-2. Questions et discussions

Si vous trouvez des erreurs dans ce tutoriel, s'il vous plaît informez-moi (voir en haut de la page). Veuillez noter que, en raison du volume élevé de commentaires que je reçois, je ne peux pas répondre à des questions concernant votre application. Assurez-vous d'avoir lu la FAQ vogella, peut-être la réponse s'y trouve déjà.

7. Liens et littérature

7-1. Code source

7-2. Ressources animation Android

7-3. Ressources vogella

8. Remerciements Developpez

Vous pouvez retrouver l'article original à l'adresse Android Animations - Tutorial. Nous remercions Lars Vogel qui nous a aimablement autorisés à traduire et héberger ses articles. Nous remercions aussi Mishulyna pour sa traduction, Feanorin pour sa relecture technique ainsi que ced pour sa relecture orthographique.

Les commentaires et les suggestions d'amélioration sont les bienvenus, alors, après votre lecture, n'hésitez pas. Commentez Donner une note à l'article (5).