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.
// Utiliser la couche matérielle
myView.animate
(
).translationX
(
400
).withLayer
(
);
Pour optimiser les performances, vous pouvez aussi laisser ViewPropertyAnimator utiliser une disposition matérielle.
// 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.
// 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é.
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.
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.
<?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.
<?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.
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"
, 0
f);
fadeOut.setDuration
(
2000
);
ObjectAnimator mover =
ObjectAnimator.ofFloat
(
aniView, "translationX"
, -
500
f, 0
f);
mover.setDuration
(
2000
);
ObjectAnimator fadeIn =
ObjectAnimator.ofFloat
(
aniView, "alpha"
, 0
f, 1
f);
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.
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.