onAnimationEnd не вызывается, onAnimationStart работает нормально - PullRequest
43 голосов
/ 29 марта 2011

У меня есть ScrollView в PopupWindow. Я анимирую содержимое ScrollView с помощью TranslateAnimation.

Когда анимация запускается, вызывается прослушиватель onAnimationStart, но onAnimationEnd не вызывается. Есть идеи?

Макет:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:background="@drawable/popup_window_bg"
   android:layout_width="match_parent"
   android:layout_height="wrap_content">
  <View
     android:layout_width="@dimen/toolbar_padding_left"
     android:layout_height="@dimen/toolbar_height"/>
  <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+web/toolbar"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:scrollbars="none"
     android:visibility="invisible">
    <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">

       ...

    </LinearLayout>
  </ScrollView>
</LinearLayout>

Код анимации:

mToolbar = mPopupContents.findViewById( R.web.toolbar );
TranslateAnimation anim =
    new TranslateAnimation(0, 0, -60, 0);
anim.setDuration(1000);
anim.setAnimationListener(new Animation.AnimationListener() {
        public void onAnimationStart(Animation a) {
            Log.d(LOGTAG, "---- animation start listener called"  );
        }
        public void onAnimationRepeat(Animation a) {}
        public void onAnimationEnd(Animation a) {
            Log.d(LOGTAG, "---- animation end listener called"  );
        }
    });
mToolbar.startAnimation(anim);

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

Ответы [ 14 ]

57 голосов
/ 14 декабря 2012

AnimationEnd не является надежным.Если вы не хотите переписывать свой код с помощью пользовательских представлений, которые переопределяют OnAnimationEnd, используйте postDelayed.

Вот пример кода:

final FadeUpAnimation anim = new FadeUpAnimation(v);
anim.setInterpolator(new AccelerateInterpolator());
anim.setDuration(1000);
anim.setFillAfter(true);
new Handler().postDelayed(new Runnable() {
    public void run() {
        v.clearAnimation();
        //Extra work goes here
    }
}, anim.getDuration());
v.startAnimation(anim);

Хотя это МОЖЕТ казаться уродливым, я могугарантия, что это очень надежно.Я использую его для ListViews, которые вставляют новые строки при удалении с анимацией в другие строки.Стресс-тестирование слушателя с помощью AnimationEnd оказалось ненадежным.Иногда AnimationEnd никогда не срабатывал.Возможно, вы захотите повторно применить любое преобразование в функции postDelayed, если анимация не завершена полностью, но это действительно зависит от того, какой тип анимации вы используете.

9 голосов
/ 19 января 2013

После того, как я не помню, как могут читать сообщения и сколько дней потратили на поиск решения этой проблемы, я обнаружил, что если объект для перемещения находится не в области экрана (например, расположен вне координат экрана), обратный вызов OnAnimationEnd не вызывается. Возможно, анимация завершается неудачно сразу после запуска (вызван метод start, я кодировал слушателя), но в logcat ничего не записывается. Может быть, это не совсем ваш случай, но это, наконец, решило мою проблему и надеюсь, что оно вам тоже поможет.

7 голосов
/ 13 марта 2015

Убедитесь, что вы ИСПОЛЬЗУЕТЕ view.startAnimation(Animation) И НЕ view.setAnimation(Animation).Эта простая путаница может быть проблемой.

3 голосов
/ 17 июня 2011

Кроме того, при использовании анимации не забывайте от setFillAfter() до true.

http://developer.android.com/reference/android/view/animation/Animation.html#setFillAfter(boolean)

Если значение fillAfter равно true, преобразование, выполненное этой анимацией, будет сохранятьсякогда это закончено.По умолчанию false, если не установлено.Обратите внимание, что это применяется при использовании AnimationSet для цепочки анимаций.Преобразование не применяется до запуска самого AnimationSet.

anim.setFillAfter(true);
mToolbar.startAnimation(anim);
2 голосов
/ 26 октября 2014

Для любого, кто сталкивается с этим вопросом: попробуйте вместо этого использовать систему Property Animation http://developer.android.com/guide/topics/graphics/prop-animation.html

У меня было несколько проблем со старым способом анимации постепенного появления / исчезновения изображения(через AlphaAnimation).OnAnimationEnd не вызывался и т. Д. С помощью Property Animation все эти проблемы были решены.

Если вы хотите поддерживать API <11 устройств, Джейк Уортон <a href="https://github.com/JakeWharton/NineOldAndroids" rel="nofollow">https://github.com/JakeWharton/NineOldAndroids - это путь, по которому

0 голосов
/ 27 июля 2017

Сделайте это, как показано ниже

  1. сделайте анимацию окончательной
  2. вызовите ее внутри обработчика
  3. слушатель должен быть запущен один раз.
  4. очистить анимацию.

например, view.clearAnimation ();

new Hander().post(
   run() {
final TranslateAnimation ani = new TranslateAnimation(0, 0, 0, 0);
ani.setAnimationListener(mListener);
 }
);

private Animation.AnimationListener mListener = new Animation.AnimationListener() {
}
0 голосов
/ 10 февраля 2017

Когда вы запускаете команду анимации в виде, который частично находится за пределами экрана, запускается анимация и вызывается onStartListener, но анимация не запускается полностью (каким-то образом она прерывается в середине).Я предполагаю, что, поскольку представление находится за пределами экрана, оно отменяется, и, следовательно, его onFinish не вызывается.В качестве обходного пути для этого я создал собственный слушатель анимации, который запускается как обработчик и использует postDelayed для уведомления пользователя о событии окончания анимации.В Kotlin:

abstract class PartiallyOffScreenAnimationListener : Animation.AnimationListener, AnimationListener {
    override fun onAnimationRepeat(animation: Animation?) {
        onAnimationRepeat_(animation)
    }
    override fun onAnimationEnd(animation: Animation) {}

    override fun onAnimationStart(animation: Animation) {
        onAnimationStart_(animation)
        Handler().postDelayed({
            onAnimationEnd_(animation)
            animation.setAnimationListener(null)
        }, animation.duration + 50)
    }
}

Обратите внимание, что в случае, если анимация не запускается полностью, представление может остаться в несовместимом состоянии (например, анимация параметров макета может привести к странному среднему интерполяторуФактор отбрасывается. По этой причине вы должны проверить в конце обратного вызова, что представление находится в требуемом состоянии. Если нет, просто установите его вручную.

0 голосов
/ 31 марта 2016

Может быть, кто-то все еще имеет эту проблему и не нашел решения - даже несмотря на то, что читает много ответов от stackoverflow - как я!

Итак, мой случай: я использовал animatorSet и

  1. не было ни одного представления, на котором я мог бы вызвать clearAnimation,
  2. Я не вызывал свою анимацию из backgroundThread, которую вы никогда не должны делать, кстати ...

В качестве решения я позвонил animatorSet.end() прямо перед animatorSet.start()

0 голосов
/ 15 сентября 2011

Я попробовал ваш код, он отлично работает при запуске OnAnimation и inAmimationEnd, а также, после продолжительности означает, что после завершения анимации вызывается OnAnimationEnd, поэтому ваш код работает нормально

TranslateAnimation anim =new TranslateAnimation(0, 0, -60, 0);
        anim.setDuration(1000);     
        anim.setAnimationListener(new Animation.AnimationListener() {
                public void onAnimationStart(Animation a) {
                    Log.w("Start", "---- animation start listener called"  );
                }
                public void onAnimationRepeat(Animation a) {}
                public void onAnimationEnd(Animation a) {
                    Log.d(" end  ","---- animation end listener called"  );
                }
            });
            mIv.setAnimation(anim);
            mIv.startAnimation(anim);
0 голосов
/ 08 сентября 2011

Попробуйте использовать overridePendingAnimation (int, int). то есть overridePendingAnimation (0,0)

Он переопределит вашу анимацию по умолчанию, а затем вы сможете определить свою собственную анимацию, вызвав метод startAnimation с использованием объекта View.

Вот мой пример кода. Не знаю, будет ли это полезно для вас или нет.

overridePendingTransition(0,0);
//finish();
v.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.fadeout));
startActivity(new Intent(ContentManagerActivity.this,Mainmenu_activity.class));
overridePendingTransition(R.anim.fadein,0);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...