Estoy tratando de hacer una animación simple 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>
Primero debe escalar la imagen de 1.0 a 1.2 en 500 ms.
Y luego vuelva a escalarlo a 1.0 en 500 ms.
Así es como lo estoy usando:
Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);
Hace un ciclo y luego termina.
Se amplía, luego se reduce y luego se detiene.
¿Cómo puedo hacer que esto funcione según lo previsto?
Respuestas:
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
yfillEnabled
que todavía se ignoran (a propósito por alguna razón). Esto significa que,AnimationSet
lamentablemente , todavía no es fácil repetir .Para obtener más detalles, consulte la descripción general en los documentos actualizados (explica qué atributos se ignoran, cuáles funcionan y cuáles se pasan a los niños). Y para una comprensión más profunda de lo que
fillAfter
,fillBefore
yfillEnabled
de hecho hacer, ver (Chet Haase) entrada en el blog del ingeniero de ello aquí .Respuesta original
Para ampliar las respuestas de Pavel y otros: es cierto que la
<set>
etiqueta tiene errores ridículos. No se puede tratar correctamente conrepeatCount
una serie de otros atributos.Pasé unas horas averiguando qué puede y qué no puede manejar y he enviado un informe de error / problema aquí: Problema 17662
En resumen (esto se refiere a
AnimationSet
s):fuente
Descubrí que la etiqueta <set> tiene una implementación defectuosa en la clase AnimationSet .
No puede lidiar 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" />
Desafortunadamente, esto se limita a una sola animación a la vez.
No podemos definir una secuencia de animaciones de esta manera ...
fuente
Debes incluir el atributo
android:repeatCount="infinite"
Pero en la animación de "escala" no está en "conjunto"
fuente
Para obtener una animación repetida, utilicé el oyente de animación y volví a llamar a la animación cuando terminó. Esto hace que la retícula de la cámara se enfoque como una animación con corchetes.
Aquí está el diseño de 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); }
fuente
También me enfrentaba al mismo problema ... incluí android: repeatCount = "infinite" en el archivo XMl ... ahora funciona 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"/>
fuente
puedes probar este código. En su código simplemente agregue,
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.
fuente
repeatMode
debe serRESTART
oREVERSE
Intenté usar el código de Daniel para mostrar la animación el número exacto de veces y tuve un problema: la animación se mostraba aproximadamente n / 2 veces, cuando se esperaba n veces.
Así que modifiqué 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, que se muestra arriba, la animación se muestra exactamente REPEAT_COUNT veces, porque el método View.post () brinda la capacidad de comenzar una nueva animación después de terminar todas las acciones, relacionadas con la animación anterior.
fuente
debe agregar solo una línea en su código xml que sugerí a continuación.
<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>
fuente
Resolví este problema usando
android:repeatMode="reverse"
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" />
fuente
Con la versión 4.0.3 de Android SDK:
En los elementos de animación dados:
android: repeatCount = "- 1"
lo convierte en una animación infinita.
fuente
Agregue la siguiente clase 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 solo N veces, haga lo siguiente:
Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a, int N).start();
N significa número de repeticiones.
fuente
Hago la mayoría de mis cosas de manera programática y puedo llegar tarde o ser ineficiente en esto, pero esto, pero completé el objetivo de repetir el conjunto de animación (incluso tengo 2 conjuntos de animación alternos). Todo lo que hace este código es simplemente desvanecerse en una imagen, pausar, luego desvanecerse, desvanecerse en otra imagen, pausar, desvanecerse y recuperar la primera (enjuagar y repetir). Primero definí mis Imageviews:
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 controladores para lidiar con 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);
Finalmente, en lugar de crear conjuntos de animación agregando animaciones, solo los oyentes de animaciones para determinar cuándo comenzar 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 } }); }
La limpieza y la invalidación fueron solo intentos anteriores y hacer que esto funcione correctamente. No sé si son obligatorios o no.
Espero que esto ayude a alguien.
Ryan
fuente
Tengo esto para ir ... Estaba tratando de obtener una vista para rotar en un círculo continuamente.
anterior, estaba usando Rotation.setRepeatMode (-1) pero eso no funcionó. cambió a setrepeatcount y funciona. Esto está en Jelly Bean 4.2.2
ObjectAnimator rotation = ObjectAnimator.ofFloat(myview, "rotation", 360).setDuration(2000); rotation.setRepeatMode(-1); rotation.setRepeatCount(Animation.INFINITE); rotation.start();
fuente
Me enfrenté al mismo problema, pero no quería hacer nada de sincronización en Java debido al punto que el hilo de la interfaz de usuario puede estar muy ocupado a veces. La bandera INFINITE no funciona para la etiqueta de conjunto. Así que resolví el problema con un pequeño fragmento 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.
fuente
He resuelto este problema. Esta es mi versión de la solució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) { } } }
fuente
Me encontré con este problema mientras trabajaba en una aplicación compatible con versiones anteriores. ¡muy frustrante! Terminé codificando una buena clase de solución alternativa que se puede llamar desde onCreate y que iniciará cualquier recurso de animación en un bucle indefinido.
la clase, AnimationLooper, está disponible aquí: https://gist.github.com/2018678
fuente
Después de investigar las respuestas de Internet, encontré una solución que funciona perfectamente para mí. (Y sí, repeatCount y repeatMode tienen muchos errores cuando se usan 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: (Resuélvalo introduciendo un ligero retraso una vez 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 muchas clases sobre las que te gustaría investigar, pero actualmente estoy usando objectAnimator, que es muy flexible. No recomendaría usar Animation o AnimationUtils:
fuente
Es necesario escuchar la finalización de la primera animación y luego reiniciar la animación en la devolución de llamada de onStopAnimation, pruebe este enlace
fuente
Un pequeño ajuste a la respuesta de @Danufr para evitar que los recursos se carguen nuevamente.
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);
fuente
Resolví este problema usando 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 } });
fuente
está funcionando bien
GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable(); gifDrawable.setLoopCount(0);
fuente
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 unitarias, mis pruebas solían atascarse en este ciclo infinito. Finalmente, específicamente para mi caso, necesitaba repetir esta animación un número específico de veces. Entonces, agregué manualmente copias de mi animación en anim_rot.xml en cascada agregando el valor de compensación . Sé que es malo y no funcionará para muchos, pero fue 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 repetirlo veces específicas agregando valores de compensación.
fuente
Intente agregar el código a un hilo de bucle o una declaración while / for
fuente