Анимация Android не повторяется


85

Я пытаюсь сделать простую анимацию, которая повторялась бы несколько раз (или бесконечно).
Вроде android:repeatCountне работает!
Вот мой ресурс по анимации /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>

Сначала он должен масштабировать изображение от 1,0 до 1,2 размера за 500 мс.
А затем уменьшите его до 1,0 за 500 мс.
Вот как я его использую:

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

Он делает один цикл и затем завершается.
Он увеличивается, затем уменьшается, а затем останавливается.

Как я могу заставить эту работу работать так, как задумано?


Что такое imgView в вашем Java-коде?
clifgray

Ответы:


63

Обновление: еще в сентябре 2011 года инженер Android по большей части исправил эту проблему. Атрибуты, которые игнорировались в XML, теперь работают, за исключением repeatCountи fillEnabledкоторые по-прежнему игнорируются (по какой-то причине специально). Это означает, что, к AnimationSetсожалению, повторить одно и то же непросто .

Для получения дополнительной информации см. Обзор в обновленной документации (объясняется, какие атрибуты игнорируются, какие работают, а какие передаются дочерним элементам). И для более глубокого понимания того , что fillAfter, fillBeforeи на fillEnabledсамом деле сделать, см (Chet Haase) в блоге инженера об этом здесь .


Оригинальный ответ

Чтобы расширить ответы Павла и других: это правда, что <set>тег до смешного содержит ошибки. Он не может правильно справиться repeatCountи с рядом других атрибутов.

Я потратил несколько часов на то, чтобы выяснить, с чем он может и чего не может справиться, и отправил отчет об ошибке / проблему здесь: Проблема 17662

В итоге (это касается AnimationSets):

setRepeatCount () / android: repeatCount

Этот атрибут (как и repeatMode) не работает в коде или XML. Это затрудняет повторение всего набора анимаций.

setDuration () / android: продолжительность

Установка этого параметра в AnimationSet в коде РАБОТАЕТ (отменяет все длительности дочерних анимаций), но не при включении в тег в XML

setFillAfter () / android: fillAfter

Это работает как в коде, так и в XML для тега. Как ни странно, мне удалось заставить его работать без необходимости устанавливать для fillEnabled значение true.

setFillBefore () / android: fillBefore

Кажется, не влияет / игнорируется как в коде, так и в XML

setFillEnabled () / android: fillEnabled

Кажется, что не влияет / игнорируется как в коде, так и в XML. Я все еще могу заставить fillAfter работать даже без включения fillEnabled или установки для fillEnabled значения false.

setStartOffset () / android: startOffset

Это работает только в коде, а не в XML.


48

Я обнаружил, что тег <set> имеет некорректную реализацию в классе AnimationSet .
Он не может правильно работать с repeatCount .
Что мы можем сделать - это установить repeatCount прямо в теге <scale> .

Этот ресурс XML работает хорошо:

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

К сожалению, это ограничено только одной анимацией одновременно.
Мы не можем таким образом определить последовательность анимаций ...


Я запускаю 2 анимации в наборе, и они не доставляют мне никаких проблем. скажите, пожалуйста, о какой проблеме вы говорите? какая ошибка? на данный момент работает над 1.6 sdk
AZ_

Объявление repeatCount в xml работает, но не в коде
onmyway133

39

Вы должны включить атрибут

android:repeatCount="infinite"

Но в вашей «масштабной» анимации не в «наборе»


1
но будут ли эти анимации ждать завершения предыдущей? спасибо
filthy_wizard

Спасибо, это сработало! Программная установка не выполнялась по какой-либо причине.
Cherry-wave

Благодарность! Это сработало. Но это непрерывно. Можно ли, чтобы это происходило каждые 5 секунд?
d34th4ck3r 02

32

Чтобы получить повторяющуюся анимацию, я использовал прослушиватель анимации и снова вызвал анимацию, когда она закончилась. Это делает фокусировку сетки камеры как анимацию с скобками.

Вот макет анимации 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>

Вот код 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);
}

2
Я должен быть правильный ответ. Работает на всех уровнях устройств и ОС
Встреча

мне это тоже помогло, но я удалил эти две строки из метода End Animation anim = AnimationUtils.loadAnimation (BuzzFinderActivity.this, R.anim.crosshair_focusing); anim.setAnimationListener (это);
аида

10

Я также столкнулся с той же проблемой ... я включил android: repeatCount = "infinite" в файл XMl .. теперь он работает нормально ...

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


9

вы можете попробовать этот код. В вашем коде просто добавьте,

firstAnimation.setRepeatCount(5);

Это будет повторять анимацию в течение определенного времени.

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

Это будет повторять анимацию бесконечно.


4
repeatModeдолжно быть либо, RESTARTлибоREVERSE
xinthink

это именно то, что я хочу, установить динамически на бесконечность.
Варун Чаудхари

2
setRepeat не работает согласно code.google.com/p/android/issues/detail?id=17662
ElliotM

4

Я попытался использовать код Дэниела, чтобы показывать анимацию точное количество раз, и у меня возникла проблема: анимация показывалась примерно n / 2 раз, тогда как ожидалось n раз.

Итак, я изменил код Дэниела:

//...
@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);
            }
        }  
    } 
}
//... 

При использовании варианта, показанного выше, анимация показывается точно REPEAT_COUNT раз, поскольку метод View.post () дает возможность начать новую анимацию после завершения всех действий, связанных с предыдущей анимацией.


3

вам нужно добавить только одну строку в свой xml-код, который я предложил ниже.

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

3

Я решил эту проблему, используя android:repeatMode="reverse"ранее в своем проекте.

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

2

С Android SDK версии 4.0.3:

В данных элементах анимации:

android: repeatCount = "- 1"

делает его бесконечной анимацией.


Благодарность! Он отлично работает на 4.2 без какого-либо обходного пути
ruX

2

Добавьте в свой проект следующий класс:

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

Для бесконечного цикла просмотра сделайте следующее:

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

Если вы хотите повторить анимацию только N раз, сделайте следующее:

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

N означает количество повторений.


1

Я делаю большую часть своих вещей программно, и я могу опоздать или неэффективно в этом, но это, но я выполнил цель набора повторяющейся анимации (у меня даже есть 2 набора чередующихся анимаций). Все, что делает этот код, - это просто исчезает одно изображение, приостанавливается, затем исчезает, исчезает на другом изображении, приостанавливается, исчезает и возвращается к первому (промыть и повторить). Сначала я определил свои изображения:

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

Затем я сделал два таймера, таймеры задач и обработчики, чтобы иметь дело с тем, когда начинать и останавливать каждую анимацию:

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

Наконец, вместо того, чтобы создавать наборы анимации путем добавления анимаций, я просто использую слушатели анимации, чтобы определить, когда начинать каждую анимацию:

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

        }
    });
}    

Очистка и аннулирование там, где только предыдущие попытки и правильная работа этой вещи. Не знаю, нужны они или нет.

Надеюсь, это кому-то поможет.


Райан


1

Мне нужно это сделать ... Я пытался заставить вид непрерывно вращаться по кругу.

ранее я использовал Rotation.setRepeatMode (-1), но это не сработало. перешел на setrepeatcount и все работает. Это на мармеладке 4.2.2

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

0

Я столкнулся с той же проблемой, но не хотел делать какие-либо временные действия в Java из-за того, что поток пользовательского интерфейса иногда может быть очень занят. Флаг INFINITE не работает для установленного тега. Итак, я решил проблему с помощью небольшого фрагмента кода:

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

со следующим 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" />

Где mIcon - это ImageView из моего макета.


0

Я решил эту проблему. Это моя версия исправления:

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

    }

}

}

0

я только что столкнулся с этой проблемой, когда работал над обратно совместимым приложением. так обидно! Я закончил тем, что написал хороший обходной класс, который можно вызвать из onCreate, и он запустит любой ресурс анимации в неопределенный цикл.

класс AnimationLooper доступен здесь: https://gist.github.com/2018678


0

Изучив ответы из Интернета, я нашел решение, которое идеально мне подходит. (И да, repeatCount и repeatMode чрезвычайно глючны при использовании вместе с 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>

В действии: (Решите это, добавив небольшую задержку после окончания анимации).

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

Есть много классов, которые вы хотели бы изучить, но в настоящее время я использую objectAnimator, который очень гибок. Я бы не рекомендовал использовать Animation или AnimationUtils:

  • Анимация
  • AnimationUtils
  • Аниматор
  • Аниматор
  • AnimatorListener
  • AnimatorListenerAdapter

0

Нужно прослушать завершение первой анимации, а затем повторно запустить анимацию в обратном вызове onStopAnimation, попробуйте эту ссылку


0

Небольшая настройка ответа @Danufr, чтобы сэкономить ресурсы от повторной загрузки.

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

0

Я решил эту проблему с помощью потока.

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

        }
    });


0

В моем случае ни одно из вышеперечисленных решений не помогло. Решение Danuofr действительно работало для набора анимации, но когда я проводил модульное тестирование, мои тесты застревали в этом бесконечном цикле. Наконец, что касается моего случая, мне нужно было повторить эту анимацию определенное количество раз. Итак, я вручную добавил копии своей анимации в anim_rot.xml каскадно, добавив значение смещения . Я знаю, что это плохо и для многих не сработает, но в моем случае это был единственный обходной путь.

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>

Я сделал это, чтобы повторить анимацию 3 раза. Вы можете добавить больше копий, чтобы повторить это определенное время, добавив значения смещения.


-1

Попробуйте добавить код в поток цикла или оператор while / for


Что ж, единственное решение, которое я нашел, - это избегать использования тега set.
Павел Чернов
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.