Estou tentando fazer uma animação simples que se repetiria várias vezes (ou infinitamente).
Parece que android:repeatCount
não funciona!
Aqui está meu recurso de animação 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>
Primeiro, ele deve dimensionar a imagem de 1,0 a 1,2 em 500 ms.
E, em seguida, reduza para 1,0 em 500 ms.
Aqui está como estou usando:
Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);
Faz um ciclo e depois termina.
Ele aumenta, diminui e então para.
Como posso fazer isso funcionar conforme o esperado?
Respostas:
Atualização: em setembro de 2011, um engenheiro do Android corrigiu esse problema na maior parte. Os atributos que foram ignorados em XML agora funcionam, com exceção de
repeatCount
efillEnabled
que ainda são ignorados (propositalmente por algum motivo). Isso significa que ainda não é fácil repetir um,AnimationSet
infelizmente.Para obter detalhes, consulte a visão geral nos documentos atualizados (explica quais atributos são ignorados, quais funcionam e quais são passados para os filhos). E para uma compreensão mais profunda do que
fillAfter
,fillBefore
efillEnabled
realmente faz, consulte a postagem do blog do engenheiro (Chet Haase) sobre isso aqui .Resposta Original
Para expandir as respostas de Pavel e outros: é verdade que a
<set>
etiqueta é ridiculamente cheia de erros. Ele não pode lidar corretamente comrepeatCount
uma série de outros atributos.Passei algumas horas descobrindo o que ele pode e não pode resolver e enviei um relatório de bug / problema aqui: Issue 17662
Em resumo (isso diz respeito
AnimationSet
s):fonte
Descobri que a tag <set> tem uma implementação com erros na classe AnimationSet .
Ele não pode lidar corretamente com repeatCount .
O que podemos fazer - é definir repeatCount diretamente na tag <scale> .
Este recurso XML está funcionando bem:
<?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" />
Infelizmente, isso é limitado a apenas uma animação por vez.
Não podemos definir uma sequência de animações desta forma ...
fonte
Você deve incluir o atributo
android:repeatCount="infinite"
Mas em sua animação de "escala" não em "conjunto"
fonte
Para obter uma animação repetida, usei o ouvinte de animação e chamei a animação novamente quando ela terminou. Isso faz uma retícula da câmera focalizando como uma animação com colchetes.
Aqui está o layout de animação 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>
Aqui está o 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); }
fonte
Eu também estava enfrentando o mesmo problema .. incluí android: repeatCount = "infinite" no arquivo XMl .. agora está funcionando bem ...
<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"/>
fonte
você pode tentar este código. Em seu código, basta adicionar,
firstAnimation.setRepeatCount(5);
Isso irá repetir a animação por um tempo definido
firstAnimation.setRepeatCount(Animation.INFINITE); firstAnimation.setRepeatMode(Animation.INFINITE);
Isso irá repetir a animação indefinidamente.
fonte
repeatMode
deve serRESTART
ouREVERSE
Tentei usar o código de Daniel para mostrar a animação número exato de vezes e tive um problema: a animação foi mostrada aproximadamente n / 2 vezes, quando n vezes o esperado.
Então, eu modifiquei o 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 a variante, mostrada acima, a animação é mostrada exatamente REPEAT_COUNT vezes, porque o método View.post () dá a capacidade de iniciar uma nova animação após terminar todas as ações, relacionadas com a animação anterior.
fonte
você tem que adicionar apenas uma linha em seu código xml que sugeri abaixo.
<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>
fonte
Resolvi esse problema usando
android:repeatMode="reverse"
before no meu projeto.<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" />
fonte
Com o Android SDK versão 4.0.3:
Nos elementos de animação fornecidos:
android: repeatCount = "- 1"
torna uma animação infinita.
fonte
Adicione a seguinte classe ao seu projeto:
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 um loop infinito de sua visualização, faça o seguinte:
Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a).start();
Se você quiser repetir a animação apenas N vezes, faça o seguinte:
Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a, int N).start();
N representa o número de repetições.
fonte
Eu faço a maioria das minhas coisas de forma programática e posso estar atrasado ou ineficiente nisso, mas concluí o objetivo do conjunto de animações de repetição (eu até tenho 2 conjuntos de animação alternados). Tudo o que esse código faz é simplesmente desaparecer em uma imagem, pausar, depois desaparecer, aparecer outra imagem, pausar, desaparecer e trazer de volta a primeira (enxágue e repita). Eu primeiro defini minhas visualizações de imagens:
final ImageView purple = (ImageView)findViewById(R.id.purp); final ImageView yellow = (ImageView)findViewById(R.id.yell); purple.setVisibility(View.INVISIBLE); yellow.setVisibility(View.INVISIBLE);
Em seguida, criei dois cronômetros, cronômetros de tarefa e manipuladores para lidar com quando iniciar e parar cada animação:
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 fim, em vez de criar conjuntos de animação adicionando animações, apenas animarei os ouvintes para determinar quando iniciar cada animação:
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 } }); }
A animação limpa e invalida onde apenas as tentativas anteriores e fazer isso funcionar direito. Não sei se são obrigatórios ou não.
Espero que isso ajude alguém.
Ryan
fonte
eu tenho que ir ... eu estava tentando obter uma visão para girar continuamente em um círculo.
Anteriormente eu estava usando a rotação.setRepeatMode (-1), mas isso não funcionou. mudou para setrepeatcount e funciona. Isso está no Jelly Bean 4.2.2
ObjectAnimator rotation = ObjectAnimator.ofFloat(myview, "rotation", 360).setDuration(2000); rotation.setRepeatMode(-1); rotation.setRepeatCount(Animation.INFINITE); rotation.start();
fonte
Eu enfrentei o mesmo problema, mas não queria fazer nenhuma coisa de temporização em Java por causa do ponto que o thread de interface do usuário pode estar muito ocupado às vezes. O sinalizador INFINITE não funciona para a tag definida. Resolvi o problema com um pequeno trecho 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); } });
com o seguinte 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" />
Onde mIcon é um ImageView do meu layout.
fonte
Eu resolvi esse problema. Esta é minha versão da correção:
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) { } } }
fonte
Acabei de encontrar esse problema enquanto trabalhava em um aplicativo compatível com versões anteriores. tão frustrante! Acabei desenvolvendo uma classe de solução alternativa que pode ser chamada de onCreate e iniciará qualquer recurso de animação em um loop indefinido.
a classe, AnimationLooper, está disponível aqui: https://gist.github.com/2018678
fonte
Depois de pesquisar as respostas na internet, encontrei uma solução que funciona perfeitamente para mim. (E sim, repeatCount e repeatMode são extremamente problemáticos quando usados junto com 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>
Em atividade: (Resolva introduzindo um pequeno atraso após o término da animação).
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);
Existem muitas classes que você gostaria de pesquisar, mas atualmente estou usando o objectAnimator, que é altamente flexível. Eu não recomendaria usar Animation ou AnimationUtils:
fonte
É necessário ouvir a conclusão da primeira animação e reiniciá-la no retorno da chamada onStopAnimation, tente este link
fonte
Pequenos ajustes na resposta @Danufr para evitar que recursos sejam carregados novamente.
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);
fonte
Resolvi esse problema usando thread.
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 } });
fonte
está funcionando bem
GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable(); gifDrawable.setLoopCount(0);
fonte
Nenhuma das soluções acima funcionou no meu caso. A solução de Danuofr funcionou para o conjunto de animação, mas quando eu estava fazendo testes de unidade, meus testes costumavam ficar presos neste loop infinito. Por fim, específico para o meu caso, precisei repetir essa animação várias vezes. Portanto, adicionei manualmente cópias da minha animação em anim_rot.xml em cascata adicionando o valor de deslocamento . Eu sei que é ruim e não funcionará para muitos, mas foi a única solução para o meu 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>
Fiz isso para repetir a animação 3 vezes. Você pode adicionar mais cópias para repetir vezes específicas, adicionando valores de deslocamento.
fonte
Tente adicionar o código a um thread em loop ou a uma instrução while / for
fonte