La animación de Android no se repite

Estoy tratando de hacer una animación sencilla que se repita varias veces (o infinitamente).
Parece que android:repeatCount no funciona!
Aquí está mi recurso de animación 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> 

En primer lugar, debe escalar la imagen de 1,0 a 1,2 tamaño en 500 ms.
Y luego escala de nuevo a 1,0 en 500 ms.
Aquí es cómo lo estoy usando:

 Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation); imgView.startAnimation(firstAnimation); 

Hace un ciclo y luego termina.
Se escala hacia arriba, luego se reduce y luego se detiene.

¿Cómo puedo hacer que esto funcione según lo previsto?

Actualización: En Septiembre de 2011 un ingeniero de Android solucionó este problema en su mayor parte. Los atributos que se ignoraron en XML ahora funcionan, con la excepción de repeatCount y fillEnabled que todavía se ignoran (a propósito por alguna razón). Esto significa que todavía no es fácil repetir un AnimationSet desgracia.

Para más detalles, consulte la descripción general en los documentos actualizados (explica qué atributos se ignoran, qué trabajo y qué se transmiten a los niños). Y para una comprensión más profunda de lo que fillAfter , fillBefore y fillEnabled realmente lo hacen, vea el blog del ingeniero (Chet Haase) sobre esto aquí .


Respuesta Original

Para ampliar las respuestas de Pavel y otros: es cierto que la etiqueta <set> es ridículamente buggy. No puede funcionar correctamente con repeatCount y una serie de otros atributos.

Pasé unas cuantas horas averiguando lo que puede y no puedo tratar y he presentado un informe de fallo / problema aquí: Número 17662

En resumen (esto concierne a AnimationSet s):

SetRepeatCount () / android: repeatCount

Este atributo (así como repeatMode) no funciona en código o XML. Esto hace que sea difícil repetir todo un conjunto de animaciones.

SetDuration () / android: duración

Establecer esto en un AnimationSet en el código WORKS (anula todas las duraciones de las animaciones infantiles), pero no cuando se incluye en la etiqueta en XML

SetFillAfter () / android: fillAfter

Esto funciona en código y XML para la etiqueta. Curiosamente lo he conseguido para trabajar también sin la necesidad de establecer fillEnabled a true.

SetFillBefore () / android: fillBefore

Parece que no tiene efecto / se ignora en código y XML

SetFillEnabled () / android: fillEnabled

Parece no tener ningún efecto / ignorado en código y XML. Todavía puedo obtener fillAfter para trabajar incluso sin incluir fillEnabled o establecer fillEnabled a false.

SetStartOffset () / android: startOffset

Esto funciona sólo en código y no en XML.

He encontrado que la etiqueta <set> tiene implementación buggy en la clase AnimationSet .
No puede funcionar correctamente con repeatCount .
Lo que podemos hacer – es establecer repeatCount directamente en la etiqueta <scale> .

Este recurso XML funciona 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" /> 

Por desgracia, esto se limita a una sola animación a la vez.
No podemos definir una secuencia de animaciones de esta manera …

Debe incluir el atributo

 android:repeatCount="infinite" 

Pero en su "escala" de animación no en "conjunto"

Para obtener una animación de repetición que utiliza el oyente de animación, y llamó a la animación de nuevo cuando terminó. Esto hace un reticule de la cámara que se centra como animación con los corchetes.

Aquí está el diseño de la animación 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> 

Aquí está el código 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); } 

Puede probar este código. En su código sólo tiene que añadir,

 firstAnimation.setRepeatCount(5); 

Esto repetirá la animación por un tiempo definido

 firstAnimation.setRepeatCount(Animation.INFINITE); firstAnimation.setRepeatMode(Animation.INFINITE); 

Esto repetirá la animación indefinidamente.

Yo también estaba enfrentando el mismo problema .. i incluido android: repeatCount = "infinito" en el archivo XMl..now su funcionamiento 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"/> 

Intenté usar el código de Daniel para mostrar la animación número exacto de veces y tuve un problema: la animación se mostró aproximatily n / 2 veces, cuando n veces se esperaba.

Así que he modificado el código 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); } } } } //... 

Usando la variante, mostrada arriba, la animación se muestra exacto REPEAT_COUNT veces, porque el método View.post () da la habilidad de iniciar una nueva animación después de terminar todas las acciones, relacionadas con la animación anterior.

Con android sdk versión 4.0.3:

En los elementos de animación dados:

Android: repeatCount = "- 1"

Lo convierte en una animación infinita.

Agregue la clase siguiente a su proyecto:

 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) { } } 

Para un bucle infinito de su vista, haga lo siguiente:

 Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a).start(); 

Si desea repetir la animación sólo para N veces, haga lo siguiente:

 Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a, int N).start(); 

N representa el número de repeticiones.

Hago la mayor parte de mi materia programmatically y puedo llegar tarde o ineficaz en esto pero esto pero terminé la meta del animationset de la repetición (yo incluso tengo 2 juegos alternos de la animación). Todo este código es simplemente se desvanecen en una imagen, pausa, luego se desvanecen, se desvanecen en otra imagen, hacen una pausa, se funden y devuelven el primero (enjuague y repita). Primero definí mis imágenes:

  final ImageView purple = (ImageView)findViewById(R.id.purp); final ImageView yellow = (ImageView)findViewById(R.id.yell); purple.setVisibility(View.INVISIBLE); yellow.setVisibility(View.INVISIBLE); 

Luego hice dos temporizadores, temporizadores de tareas y manejadores para hacer frente a cuándo iniciar y detener cada animación:

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

Por último, en lugar de crear conjuntos de animación mediante la adición de animaciones, sólo animaciones escuchas para determinar cuándo iniciar cada animación:

 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 } }); } 

El clearanimation y invalidate donde acaba de intentos anteriores y conseguir que esta cosa funcione bien. No sé si son necesarios o no.

Espero que esto ayude a alguien.


Ryan

Tengo esto para ir … estaba tratando de obtener una vista para girar en un círculo continuamente.

Previous i estaba usando rotation.setRepeatMode (-1) pero eso no funcionó. Cambiado a setrepeatcount y funciona. Esto es en jelly bean 4.2.2

  ObjectAnimator rotation = ObjectAnimator.ofFloat(myview, "rotation", 360).setDuration(2000); rotation.setRepeatMode(-1); rotation.setRepeatCount(Animation.INFINITE); rotation.start(); 

Intente agregar el código a un hilo en bucle o una sentencia while / for

He enfrentado el mismo problema, pero no quería hacer ninguna sincronización de las cosas en Java debido al punto de que el hilo de interfaz de usuario puede estar muy ocupado a veces. El indicador INFINITE no funciona para la etiqueta set. Así que resolví el problema con un pedacito de código:

 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); } }); 

Con el siguiente XML:

 <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" /> 

Donde mIcon es un ImageView de mi diseño.

He resuelto este problema. Esta es mi versión de la corrección:

 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) { } } } 

Me encontré con este problema mientras trabajaba en una aplicación compatible con versiones anteriores. ¡muy frustrante! Terminé codificando una clase agradable de la solución que se puede llamar de onCreate y patearé cualquier recurso de la animación en un lazo indefinido.

La clase, AnimationLooper, está disponible aquí: https://gist.github.com/2018678

Después de investigar a través de las respuestas de Internet, he encontrado una solución que funciona perfectamente para mí. (Y sí, el repeatCount y repeatMode es extremadamente buggy cuando se utiliza junto con 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 actividad: (Resolverlo introduciendo un ligero retraso después de finalizada la animación).

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

Hay un montón de clases que le gustaría a la investigación, pero actualmente estoy usando objectAnimator que es muy flexible. Yo no recomendaría usar Animación o AnimationUtils:

  • Animación
  • AnimationUtils
  • Animador
  • AnimatorInflater
  • AnimatorListener
  • AnimatorListenerAdapter

Uno necesita escuchar para la terminación de la primera animación, a continuación, volver a iniciar la animación en onStopAnimation volver a llamar, dar una oportunidad a este enlace

Poco ajustar a @Danufr respuesta para ahorrar recursos de la carga de nuevo.

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

He resuelto este problema utilizando reverso antes en mi proyecto.

<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" />

He resuelto este problema mediante el hilo.

 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 } }); 

Esta funcionando bien

  GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable(); gifDrawable.setLoopCount(0); 

Ninguna de las soluciones anteriores funcionó en mi caso. La solución de Danuofr funcionó para el conjunto de animación, pero cuando estaba haciendo pruebas de unidad, mis pruebas solían quedar atrapadas en este bucle infinito. Finalmente, específico para mi caso, necesitaba repetir este número específico de animaciones de veces. Por lo tanto, agregé manualmente copias de mi animación en anim_rot.xml de una manera en cascada añadiendo el valor de desplazamiento . Sé que es malo y no funcionará para muchos pero era la única solución para mi caso.

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> 

Hice esto para repetir la animación 3 veces. Puede agregar más copias para repetirlas en momentos específicos añadiendo valores de desplazamiento.

  • Android: agregar vista con animación de expansión (sin parpadear)
  • ¿Efecto de desplazamiento personalizado para scrollview?
  • El interruptor de actividad de Android pierde la pantalla completa temporalmente
  • Establecer lista de animación de android por programación
  • Cómo crear un GIF animado de JPEGs en Android (desarrollo)
  • Animaciones de widget de pantalla de inicio de Android
  • ¿Es posible tener un dibujo animado?
  • Animación de Flip de Tarjeta entre Actividades
  • Tween animación en una lona en una vista personalizada
  • Animación personalizada en Android
  • Pausa de reproducción de Android y problema de reproducción
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.