Próbuję zrobić prostą animację, która będzie się powtarzać kilka razy (lub w nieskończoność).
Wygląda na to, że android:repeatCount
nie działa!
Oto mój zasób animacji z /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>
Najpierw powinien przeskalować obraz od rozmiaru 1,0 do 1,2 w 500 ms.
A następnie skaluj go z powrotem do 1,0 w 500 ms.
Oto jak go używam:
Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);
Wykonuje jeden cykl, a następnie się kończy.
Skala w górę, potem w dół, a następnie zatrzymuje się.
Jak mogę to zrobić zgodnie z przeznaczeniem?
Odpowiedzi:
Aktualizacja: We wrześniu 2011 r. Inżynier Android rozwiązał ten problem w większości. Atrybuty, które zostały zignorowane w XML teraz działają, z wyjątkiem
repeatCount
ifillEnabled
które są nadal ignorowane (celowo z jakiegoś powodu). Oznacza to, że niestety nadal nie jest łatwo powtórzyćAnimationSet
.Aby uzyskać szczegółowe informacje, zapoznaj się z omówieniem w zaktualizowanych dokumentach (wyjaśnia, które atrybuty są ignorowane, które działają, a które są przekazywane dzieciom). Aby dowiedzieć się więcej o tym
fillAfter
, cofillBefore
ifillEnabled
faktycznie robią, przeczytaj wpis na blogu inżyniera (Chet Haase) o tym tutaj .Oryginalna odpowiedź
Aby rozwinąć odpowiedzi Pawła i innych: to prawda, że
<set>
tag jest śmiesznie błędny. Nie radzi sobie poprawnie zrepeatCount
wieloma innymi atrybutami.Spędziłem kilka godzin, zastanawiając się, z czym może, a czego nie może sobie poradzić, i przesłałem zgłoszenie błędu / problem tutaj: numer 17662
Podsumowując (dotyczy to
AnimationSet
s):źródło
Zauważyłem, że tag <set> ma wadliwą implementację w klasie AnimationSet .
Nie radzi sobie poprawnie z repeCount .
Co możemy zrobić - to ustawić repeatCount bezpośrednio w tagu <scale> .
Ten zasób XML działa dobrze:
<?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" />
Niestety jest to ograniczone do tylko jednej animacji naraz.
Nie możemy w ten sposób zdefiniować sekwencji animacji ...
źródło
Powinieneś dołączyć atrybut
android:repeatCount="infinite"
Ale w animacji „skali” nie ma „zestawu”
źródło
Aby uzyskać powtarzającą się animację, użyłem słuchacza animacji i ponownie wywołałem animację po jej zakończeniu. To sprawia, że siatka aparatu skupia się jak animacja z nawiasami.
Oto XML układu animacji
<?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>
Oto kod 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); }
źródło
Miałem również ten sam problem ... w pliku XMl umieściłem androida: repeatCount = "infinite" ... teraz działa dobrze ...
<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"/>
źródło
możesz wypróbować ten kod. W swoim kodzie po prostu dodaj,
firstAnimation.setRepeatCount(5);
Spowoduje to powtórzenie animacji przez określony czas
firstAnimation.setRepeatCount(Animation.INFINITE); firstAnimation.setRepeatMode(Animation.INFINITE);
Animacja będzie powtarzana w nieskończoność.
źródło
repeatMode
powinno być alboRESTART
alboREVERSE
Próbowałem użyć kodu Daniela, aby pokazać animację dokładną liczbę razy i miałem problem: animacja została wyświetlona mniej więcej n / 2 razy, gdy oczekiwano n razy.
Więc zmodyfikowałem kod Daniela:
//... @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); } } } } //...
Korzystając z wariantu pokazanego powyżej, animacja jest pokazana dokładnie REPEAT_COUNT razy, ponieważ metoda View.post () daje możliwość uruchomienia nowej animacji po zakończeniu wszystkich akcji związanych z poprzednią animacją.
źródło
musisz dodać tylko jedną linię w kodzie XML, który zasugerowałem poniżej.
<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>
źródło
Rozwiązałem ten problem, używając
android:repeatMode="reverse"
wcześniej w moim projekcie.<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" />
źródło
Z systemem Android SDK w wersji 4.0.3:
W podanych elementach animacji:
android: repeatCount = "- 1"
sprawia, że jest to nieskończona animacja.
źródło
Dodaj następującą klasę do swojego projektu:
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) { } }
Aby uzyskać nieskończoną pętlę widoku, wykonaj następujące czynności:
Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a).start();
Jeśli chcesz powtórzyć animację tylko N razy, wykonaj następujące czynności:
Animation a = AnimationUtils(Context, R.anim.animation); new AnimationRepeater(View, a, int N).start();
N oznacza liczbę powtórzeń.
źródło
Większość moich rzeczy robię programowo i mogę się spóźnić lub nieefektywnie na tym, ale to, ale osiągnąłem cel powtórzenia zestawu animacji (mam nawet 2 naprzemienne zestawy animacji). Wszystko, co robi ten kod, to po prostu zanikanie na jednym obrazie, pauza, a następnie zanikanie, zanikanie na innym obrazie, pauza, zanikanie i przywracanie pierwszego obrazu (przepłucz i powtórz). Najpierw zdefiniowałem moje widoki obrazu:
final ImageView purple = (ImageView)findViewById(R.id.purp); final ImageView yellow = (ImageView)findViewById(R.id.yell); purple.setVisibility(View.INVISIBLE); yellow.setVisibility(View.INVISIBLE);
Następnie stworzyłem dwa liczniki czasu, liczniki czasu zadań i programy obsługi, aby radzić sobie, kiedy rozpocząć i zatrzymać każdą animację:
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);
Wreszcie, zamiast tworzyć zestawy animacji przez dodawanie animacji, po prostu słuchacze animacji określają, kiedy rozpocząć każdą animację:
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 } }); }
Wyraźna animacja i unieważnienie, gdzie tylko poprzednie próby i doprowadzenie tego do prawidłowego działania. Nie wiem, czy są wymagane, czy nie.
Mam nadzieję, że to komuś pomoże.
Ryan
źródło
mam to do zrobienia ... próbowałem uzyskać widok obracający się w kółko w sposób ciągły.
poprzedni używałem Rotation.setRepeatMode (-1), ale to nie zadziałało. przełączony na setrepeatcount i działa. To jest na galarecie 4.2.2
ObjectAnimator rotation = ObjectAnimator.ofFloat(myview, "rotation", 360).setDuration(2000); rotation.setRepeatMode(-1); rotation.setRepeatCount(Animation.INFINITE); rotation.start();
źródło
Napotkałem ten sam problem, ale nie chciałem wykonywać żadnych czynności związanych z synchronizacją w Javie, ponieważ wątek interfejsu użytkownika może być czasami bardzo zajęty. Flaga INFINITE nie działa dla zestawu tagów. Więc rozwiązałem problem za pomocą małego fragmentu kodu:
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); } });
z następującym kodem 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" />
Gdzie mIcon to ImageView z mojego układu.
źródło
Rozwiązałem ten problem. To jest moja wersja poprawki:
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) { } } }
źródło
Właśnie natknąłem się na ten problem podczas pracy nad aplikacją kompatybilną wstecz. bardzo frustrujące! Skończyło się na tym, że napisałem fajną klasę obejścia, którą można wywołać z onCreate i która uruchomi dowolny zasób animacji w nieokreśloną pętlę.
klasa AnimationLooper jest dostępna tutaj: https://gist.github.com/2018678
źródło
Po zapoznaniu się z odpowiedziami z internetu znalazłem rozwiązanie, które działa idealnie dla mnie. (I tak, repeatCount i repeatMode są bardzo błędne, gdy są używane razem z 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>
W aktywności: (Rozwiąż to, wprowadzając niewielkie opóźnienie po zakończeniu animacji).
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);
Jest wiele klas, które chciałbyś zbadać, ale obecnie używam obiektu ObjectAnimator, który jest bardzo elastyczny. Nie polecałbym używania Animation lub AnimationUtils:
źródło
Należy posłuchać zakończenia pierwszej animacji, a następnie ponownie uruchomić animację w onStopAnimation oddzwonić, wypróbuj ten link
źródło
Mała poprawka w odpowiedzi @Danufr, aby zaoszczędzić zasoby przed ponownym załadowaniem.
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);
źródło
Rozwiązałem ten problem za pomocą wątku.
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 } });
źródło
działa dobrze
GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable(); gifDrawable.setLoopCount(0);
źródło
Żadne z powyższych rozwiązań nie zadziałało w moim przypadku. Rozwiązanie autorstwa Danuofr działało w przypadku zestawu animacji, ale kiedy wykonywałem testy jednostkowe, moje testy utknęły w tej nieskończonej pętli. Wreszcie, specyficznie dla mojego przypadku, musiałem powtórzyć tę animację określoną liczbę razy. Więc ręcznie dodałem kopie mojej animacji w anim_rot.xml w sposób kaskadowy, dodając wartość przesunięcia . Wiem, że jest to złe i nie zadziała dla wielu, ale to było jedyne obejście w moim przypadku.
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>
Zrobiłem to, aby powtórzyć animację 3 razy. Możesz dodać więcej kopii, aby powtórzyć to w określonym czasie, dodając wartości przesunięcia.
źródło
Spróbuj dodać kod do wątku pętli lub instrukcji while / for
źródło