Tutoriel pour utiliser les animations sous Android

L'API Android Property Animation

Ce tutoriel, basé sur Eclipse 4.2, Java 1.6 et Android 4.2, explique comment utiliser les animations sous Android.

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).

Article lu   fois.

Les deux auteur et traducteur

Site personnel

Traducteur :

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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. Liens et littérature

7. 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.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
Le contenu de cet article est rédigé par Lars Vogel et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.