J'essaie de faire une animation simple qui se répète plusieurs fois (ou infiniment).
Il semble que Android:repeatCount
ne fonctionne pas!
Voici ma ressource d'animation de /res/anim/first_animation.xml
:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shareInterpolator="false"
Android:repeatCount="infinite"
>
<scale
Android:interpolator="@Android:anim/decelerate_interpolator"
Android:duration="500"
Android:fromXScale="1.0"
Android:fromYScale="1.0"
Android:toXScale="1.2"
Android:toYScale="1.2"
Android:pivotX="50%"
Android:pivotY="50%"
Android:fillAfter="false" />
<scale
Android:interpolator="@Android:anim/accelerate_interpolator"
Android:startOffset="500"
Android:duration="500"
Android:fromXScale="1.2"
Android:fromYScale="1.2"
Android:toXScale="1.0"
Android:toYScale="1.0"
Android:pivotX="50%"
Android:pivotY="50%"
Android:fillAfter="false" />
</set>
D'abord, l'image doit être redimensionnée de 1,0 à 1,2 en 500 ms.
Et puis redimensionner à 1,0 en 500 ms.
Voici comment je l’utilise:
Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);
Il fait un cycle et se termine ensuite.
Il augmente, puis diminue et s’arrête.
Comment puis-je faire ce travail comme prévu?
Mise à jour: De retour en septembre 2011, un ingénieur Android a résolu ce problème pour la plupart. Les attributs qui ont été ignorés dans XML fonctionnent maintenant, à l'exception de repeatCount
et fillEnabled
qui sont toujours ignorés (exprès pour une raison quelconque). Cela signifie qu'il n'est toujours pas facile de répéter un AnimationSet
malheureusement.
Pour plus de détails, veuillez consulter l'aperçu dans la mise à jour de la documentation (explique quels attributs sont ignorés, lesquels fonctionnent et ceux qui sont transmis aux enfants). Et pour mieux comprendre ce que fillAfter
, fillBefore
et fillEnabled
font réellement, consultez le blog de l'ingénieur (Chet Haase) à ce sujet (ici } _.
Pour développer les réponses de Pavel et d’autres: il est vrai que la balise <set>
est ridiculement boguée. Il ne peut pas traiter correctement repeatCount
et un certain nombre d'autres attributs.
J'ai passé quelques heures à comprendre ce qu'il peut et ne peut pas gérer et j'ai soumis un rapport de bogue/un problème ici: Problème 17662
En résumé (cela concerne AnimationSet
s):
setRepeatCount ()/Android: repeatCount
Cet attribut (ainsi que repeatMode) ne fonctionne pas en code ou en XML. Cela rend difficile la répétition d'un ensemble d'animations.
setDuration ()/Android: durée
Définir ceci sur un AnimationSet dans le code WORKS (remplace toutes les durées des animations enfants), mais pas lorsqu'il est inclus dans la balise en XML
setFillAfter ()/Android: fillAfter
Cela fonctionne à la fois en code et en XML pour la balise. Étrangement, je l'ai obtenu pour qu'il fonctionne également sans qu'il soit nécessaire de définir fillEnabled sur true.
setFillBefore ()/Android: remplirAvant
Semble n'avoir aucun effet/ignoré dans le code et XML
setFillEnabled ()/Android: fillEnabled
Semble n'avoir aucun effet/ignoré à la fois en code et en XML. Je peux toujours faire en sorte que fillAfter fonctionne même sans inclure fillEnabled ni définir la valeur de fillEnabled à false.
setStartOffset ()/Android: startOffset
Cela ne fonctionne que dans le code et pas XML.
J'ai trouvé que <set> tag a une implémentation erronée dans la classe AnimationSet .
Il ne peut pas traiter correctement avec repeatCount .
Ce que nous pouvons faire est de définir repeatCount directement dans <scale> tag.
Cette ressource XML fonctionne bien:
<?xml version="1.0" encoding="utf-8"?>
<scale
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:interpolator="@Android:anim/accelerate_decelerate_interpolator"
Android:duration="200"
Android:fromXScale="1.0"
Android:fromYScale="1.0"
Android:toXScale="1.05"
Android:toYScale="1.05"
Android:pivotX="50%"
Android:pivotY="50%"
Android:repeatMode="reverse"
Android:fillAfter="false"
Android:repeatCount="24"
/>
Malheureusement, ceci est limité à une seule animation à la fois.
Nous ne pouvons pas définir une séquence d'animations de cette façon ...
Vous devriez inclure l'attribut
Android:repeatCount="infinite"
Mais dans votre animation "scale" pas dans "set"
Pour obtenir une animation répétée, j'ai utilisé l'écouteur d'animation et j'ai appelé l'animation à nouveau à la fin. Cela fait un réticule de caméra se concentrant comme une animation avec des crochets.
Voici la mise en page d'animation xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
<scale
Android:fromXScale="1.0"
Android:toXScale=".7"
Android:fromYScale="1.0"
Android:pivotX="50%"
Android:pivotY="50%"
Android:toYScale=".7"
Android:duration="1000"/>
<scale
Android:duration="1000"
Android:fromXScale=".7"
Android:toXScale="1.0"
Android:fromYScale=".7"
Android:pivotX="50%"
Android:pivotY="50%"
Android:toYScale="1.0"
Android:startOffset="1000"/>
</set>
Voici le code Java
public void startAnimation() {
View brackets = findViewById(R.id.brackets);
brackets.setVisibility(View.VISIBLE);
Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
anim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation arg0) {
Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
anim.setAnimationListener(this);
brackets.startAnimation(anim);
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
}
});
brackets.startAnimation(anim);
}
Je faisais également face au même problème .. J'ai inclus Android: repeatCount = "infinite" dans le fichier XMl..Maintenant, il fonctionne bien ...
<translate
Android:fromXDelta="0"
Android:toXDelta="80"
Android:duration="1000"
Android:repeatCount="infinite"
Android:repeatMode="reverse"
Android:pivotX="50%"
Android:pivotY="50%"
Android:fillAfter="true"/>
vous pouvez essayer ce code . Dans votre code, ajoutez simplement:
firstAnimation.setRepeatCount(5);
Cela va répéter l'animation pour un temps précis
firstAnimation.setRepeatCount(Animation.INFINITE);
firstAnimation.setRepeatMode(Animation.INFINITE);
Cela répétera l'animation indéfiniment.
Ajoutez la classe suivante à votre projet:
import Android.view.View;
import Android.view.animation.Animation;
public class AnimationRepeater implements Animation.AnimationListener
{
private View view;
private Animation animation;
private int count;
public AnimationRepeater(View view, Animation animation)
{
this.view = view;
this.animation = animation;
this.count = -1;
}
public AnimationRepeater(View view, Animation animation, int count)
{
this.view = view;
this.animation = animation;
this.count = count;
}
public void start()
{
this.view.startAnimation(this.animation);
this.animation.setAnimationListener(this);
}
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation)
{
if (this.count == -1)
this.view.startAnimation(animation);
else
{
if (count - 1 >= 0)
{
this.animation.start();
count --;
}
}
}
@Override
public void onAnimationRepeat(Animation animation) { }
}
Pour une boucle infinie de votre vue, procédez comme suit:
Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a).start();
Si vous souhaitez répéter l'animation seulement N fois, procédez comme suit:
Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a, int N).start();
N représente le nombre de répétitions.
J'ai essayé d'utiliser le code de Daniel pour afficher l'animation le nombre exact de fois et j'ai eu un problème: l'animation a été affichée approximativement n/2 fois, quand n fois attendue.
J'ai donc modifié le code de Daniel:
//...
@Override
public void onAnimationEnd(Animation arg0) {
mCurrentCount++;
if (mCurrentCount < REPEAT_COUNT) {
Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
anim.setAnimationListener(this);
brackets.post(new Runnable() {
@Override
public void run() {
brackets.startAnimation(anim);
}
}
}
}
//...
En utilisant la variante ci-dessus, l'animation est montrée exactement fois REPEAT_COUNT, car la méthode View.post () donne la possibilité de démarrer une nouvelle animation après avoir terminé toutes les actions, liée à l'animation précédente.
vous devez ajouter juste une ligne dans votre code XML que j'ai suggéré ci-dessous.
<scale
Android:duration="500"
Android:fromXScale="1.0"
Android:fromYScale="1.0"
Android:toXScale="1.2"
Android:toYScale="1.2"
Android:pivotX="50%"
Android:pivotY="50%"
Android:repeatCount="infinite" // just add this one line
Android:fillAfter="false"
/>
</set>
Avec Android SDK version 4.0.3:
Dans les éléments d'animation donnés:
Android: repeatCount = "- 1"
en fait une animation infinie.
J'ai résolu ce problème en utilisant reverse avant dans mon projet.
<scale
Android:interpolator="@Android:anim/decelerate_interpolator"
Android:duration="500"
Android:fromXScale="1.0"
Android:fromYScale="1.0"
Android:toXScale="1.2"
Android:toYScale="1.2"
Android:pivotX="50%"
Android:pivotY="50%"
Android:repeatMode="reverse"
Android:repeatCount="infinite"
/>
je voulais que ça aille ... J'essayais de voir une vue tourner en cercle de façon continue.
j'utilisais auparavant rotation.setRepeatMode (-1) mais cela ne fonctionnait pas. changé pour setrepeatcount et cela fonctionne. Ceci est sur Jelly Bean 4.2.2
ObjectAnimator rotation = ObjectAnimator.ofFloat(myview,
"rotation", 360).setDuration(2000);
rotation.setRepeatMode(-1);
rotation.setRepeatCount(Animation.INFINITE);
rotation.start();
Je fais la plupart de mes choses par programme et je peux être en retard ou inefficace sur celui-ci, mais cela, mais j'ai complété l'objectif de répétition animationset (j'ai même deux alternances d'animations). Tout ce code ne fait que fondre dans une image, faire une pause, puis disparaître, puis fondre dans une autre image, faire une pause, disparaître et ramener la première (rincer et répéter). J'ai d'abord défini mes images vues:
final ImageView purple = (ImageView)findViewById(R.id.purp);
final ImageView yellow = (ImageView)findViewById(R.id.yell);
purple.setVisibility(View.INVISIBLE);
yellow.setVisibility(View.INVISIBLE);
Ensuite, j'ai créé deux minuteries, des minuteries et des gestionnaires, pour commencer et arrêter chaque animation:
Timer p = new Timer();
TimerTask pu = new TimerTask() {
public void run() {
handler1.post(new Runnable() {
public void run()
{
fadein(purple);
}
});
}};
p.schedule(pu, 6000, 12000);
final Handler handler2 = new Handler();
Timer y = new Timer();
TimerTask ye = new TimerTask() {
public void run() {
handler2.post(new Runnable() {
public void run()
{
fadein(yellow);
}
});
}};
y.schedule(ye, 0, 12000);
Enfin, plutôt que de créer des ensembles d'animations en ajoutant des animations, je me contente de créer des animations pour les auditeurs afin de déterminer quand commencer chaque animation:
public void fadein (final ImageView image)
{
Animation anim = new AlphaAnimation(0, 1);
anim.setDuration(2000);
image.startAnimation(anim);
anim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation)
{
image.clearAnimation();
image.invalidate();
pause(image);
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
});
}
public void pause (final ImageView image)
{
Animation anim = new AlphaAnimation(1, 1);
anim.setDuration(2000);
image.startAnimation(anim);
anim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation)
{
image.clearAnimation();
image.invalidate();
fadeout(image);
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
});
}
public void fadeout (final ImageView image)
{
Animation anim = new AlphaAnimation(1,0);
anim.setDuration(2000);
image.startAnimation(anim);
anim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation)
{
image.clearAnimation();
image.invalidate();
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
});
}
Le clearanimation et invalider où juste tentatives précédentes et obtenir cette chose pour fonctionner correctement. Je ne sais pas si elles sont nécessaires ou non.
J'espère que ça aide quelqu'un.
Ryan
je viens de rencontrer ce problème alors que je travaillais sur une application rétro-compatible. tellement frustrant! J'ai fini par coder une classe de solution de contournement Nice qui peut être appelée depuis onCreate et lancera toute ressource d'animation dans une boucle indéfinie.
la classe, AnimationLooper, est disponible ici: https://Gist.github.com/2018678
J'ai résolu ce problème en utilisant du fil.
Button btn = (Button) findViewById(R.id.buttonpush);
final TextView textview = (TextView) findViewById(R.id.hello);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textview.setText("...................");
final Animation animationtest = AnimationUtils.loadAnimation(MainActivity.this, Android.R.anim.slide_in_left);
animationtest.setDuration(1000);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
handler.postDelayed(this, 1500);
textview.startAnimation(animationtest);
}
};
handler.postDelayed(runnable, 500); // start
handler.removeCallbacks(runnable); //STOP Timer
}
});
Aucune des solutions ci-dessus n'a fonctionné dans mon cas. La solution de Danuofr a fonctionné pour l'ensemble d'animation, mais lorsque je faisais des tests unitaires, mes tests étaient bloqués dans cette boucle infinie. Enfin, en fonction de mon cas, je devais répéter cette animation un nombre de fois spécifique. J'ai donc ajouté manuellement des copies de mon animation dans anim_rot.xml de manière cascadée en ajoutant la valeur de décalage . Je sais que c'est mauvais et que cela ne fonctionnera pas pour beaucoup, mais c'était la seule solution de contournement pour mon cas.
anim_rot.xml
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
<rotate
Android:duration="2000"
Android:fromDegrees="20"
Android:pivotX="29%"
Android:pivotY="50%"
Android:toDegrees="-20" />
<rotate
Android:duration="2000"
Android:fromDegrees="-20"
Android:pivotX="29%"
Android:pivotY="53%"
Android:startOffset="2000"
Android:toDegrees="20" />
<rotate
Android:startOffset="4000"
Android:duration="2000"
Android:fromDegrees="20"
Android:pivotX="29%"
Android:pivotY="56%"
Android:toDegrees="-20" />
<rotate
Android:duration="2000"
Android:fromDegrees="-20"
Android:pivotX="29%"
Android:pivotY="59%"
Android:startOffset="6000"
Android:toDegrees="20" />
<rotate
Android:startOffset="8000"
Android:duration="2000"
Android:fromDegrees="20"
Android:pivotX="29%"
Android:pivotY="62%"
Android:toDegrees="-20" />
<rotate
Android:duration="2000"
Android:fromDegrees="-20"
Android:pivotX="29%"
Android:pivotY="65%"
Android:startOffset="10000"
Android:toDegrees="20" />
</set>
Je l'ai fait pour répéter l'animation 3 fois. Vous pouvez ajouter plus de copies pour répéter des heures spécifiques en ajoutant des valeurs de décalage.
Little Tweak to @Danufr répond pour sauver les ressources du chargement.
operator = (ImageView) findViewById(R.id.operator_loading);
final Animation ani = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.finding_operator);
ani.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
operator.startAnimation(ani);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
operator.setAnimation(ani);
Après avoir recherché des réponses sur Internet, j'ai trouvé une solution qui me convient parfaitement. (Et oui, repeatCount et repeatMode sont extrêmement bogués lorsqu'ils sont utilisés avec animationSet).
anim_rotate_fade.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:interpolator="@Android:anim/accelerate_decelerate_interpolator"
Android:ordering="together" >
<objectAnimator
Android:duration="3000"
Android:propertyName="rotation"
Android:repeatCount="1"
Android:valueTo="360"
Android:valueType="floatType" />
<objectAnimator
Android:duration="3000"
Android:propertyName="alpha"
Android:repeatCount="1"
Android:repeatMode="reverse"
Android:valueFrom="0.0"
Android:valueTo="0.3"
Android:valueType="floatType" />
<objectAnimator
Android:duration="3000"
Android:propertyName="y"
Android:repeatCount="1"
Android:repeatMode="reverse"
Android:valueFrom="380"
Android:valueTo="430"
Android:valueType="floatType" />
</set>
En activité: (Résolvez-le en introduisant un léger retard après la fin de l’animation).
ImageView starlightImageView = new ImageView(this);
starlightImageView.setImageResource(R.drawable.starlight);
final AnimatorSet animate = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.anim_rotate_fade);
AnimatorListenerAdapter animatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
new Handler().postDelayed(new Runnable() {
@Override public void run() {
animate.start();
}
}, 1000);
}
};
animate.setTarget(starlightImageView);
animate.addListener(animatorListener);
Il y a beaucoup de cours sur lesquels vous aimeriez faire des recherches, mais j'utilise actuellement objectAnimator, qui est très flexible. Je ne recommanderais pas d'utiliser Animation ou AnimationUtils:
Il est nécessaire d’écouter la fin de la première animation, puis de la relancer dans le rappel onStopAnimation, essayez-le link
Essayez d’ajouter le code à un thread en boucle ou à une instruction while/for
Je suis confronté au même problème, mais je ne souhaite effectuer aucune opération de chronométrage en Java, car le thread d'interface utilisateur peut parfois être très occupé .. .. L'indicateur INFINITE ne fonctionne pas pour la balise set. J'ai donc résolu le problème avec un petit morceau de code:
mAnimation = (AnimationSet) AnimationUtils.loadAnimation(myContext, R.anim.blink);
mIcon.startAnimation(mAnimation);
mAnimation.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {}
public void onAnimationRepeat(Animation animation) {}
public void onAnimationEnd(Animation animation) {
mIcon.startAnimation(mAnimation);
}
});
avec le XML suivant:
<alpha
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:duration="1000"
Android:fromAlpha="0.0"
Android:toAlpha="1.0" />
<alpha
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:duration="1000"
Android:fromAlpha="0.9"
Android:startOffset="1000"
Android:toAlpha="0.0" />
Où mIcon est un ImageView de ma mise en page.
ça marche bien
GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable();
gifDrawable.setLoopCount(0);
J'ai résolu ce problème. Ceci est ma version du correctif:
public class HelloAndroidActivity extends Activity {
private static String TAG = "animTest";
private Animation scaleAnimation;
private int currentCover = 0;
private List<ImageView> imageViews = new ArrayList<ImageView>(3);
private Button btn;
private ImageView img;
/**
* Called when the activity is first created.
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate");
setContentView(R.layout.test);
img = (ImageView)findViewById(R.id.testpict);
imageViews.add(img);
img = (ImageView)findViewById(R.id.testpictTwo);
imageViews.add(img);
img = (ImageView)findViewById(R.id.testpict3);
imageViews.add(img);
scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.photo_scale);
scaleAnimation.setAnimationListener(new CyclicAnimationListener());
btn = (Button)findViewById(R.id.startBtn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageViews.get(0).startAnimation(scaleAnimation);
}
});
}
private class CyclicAnimationListener implements AnimationListener{
@Override
public void onAnimationEnd(Animation animation) {
currentCover += 1;
if(currentCover >= imageViews.size()){
currentCover = 0;
}
img = imageViews.get(currentCover);
scaleAnimation = AnimationUtils.loadAnimation(HelloAndroidActivity.this, R.anim.photo_scale);
scaleAnimation.setAnimationListener(new CyclicAnimationListener());
img.startAnimation(scaleAnimation);
}
@Override
public void onAnimationRepeat(Animation animation) {
Log.d("Animation", "Repeat");
}
@Override
public void onAnimationStart(Animation animation) {
}
}
}