Как запустить анимацию сразу после onCreate?

Я следую http://developer.android.com/guide/topics/graphics/view-animation.html#frame-animation с небольшими изменениями. Я решил сделать цикл анимации и хочу, чтобы он начинался с самого начала.

Моя анимация находится в drawable/listening.xml:

<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
    android:drawable="@drawable/l_01"
    android:duration="200" />
<item
    android:drawable="@drawable/l_02"
    android:duration="200" />
<item
    android:drawable="@drawable/l_03"
    android:duration="200" />
</animation-list>

и мой код инициализации:

 @Override public void onWindowFocusChanged(boolean hasFocus)  { 
      super.onWindowFocusChanged(hasFocus); 
      animImg = (ImageView)findViewById(R.id.listen_anim);
      animImg.setBackgroundResource(R.drawable.listening);
      anim = (AnimationDrawable) animImg.getBackground(); 
      anim.start();
 };

Все, что я вижу, это первый кадр и никаких других изображений.


person hunterp    schedule 02.09.2011    source источник
comment
Если вы следовали этому письму, то почему ваш вызов start() находится внутри инициализации, а не внутри onTouchEvent?   -  person WarrenFaith    schedule 03.09.2011
comment
Вы поместили этот код инициализации точно так, как рекомендуется в учебнике? Важно отметить, что метод start(), вызываемый для AnimationDrawable, не может быть вызван во время метода onCreate() вашей Activity, потому что AnimationDrawable еще не полностью присоединен к окну.   -  person Kheldar    schedule 03.09.2011
comment
Хорошо, но я хочу, чтобы анимация запускалась при загрузке, а не при касании, как это сделать?   -  person hunterp    schedule 03.09.2011


Ответы (7)


В мануале уже написано:

Важно отметить, что метод start(), вызываемый для AnimationDrawable, нельзя вызывать во время метода onCreate() вашей Activity, поскольку AnimationDrawable еще не полностью прикреплен к окну.

Если вы хотите воспроизвести анимацию немедленно, не требуя взаимодействия, вы можете вызвать ее из метода onWindowFocusChanged() в вашей деятельности, который будет вызываться, когда Android перенесет ваше окно в фокус.

Так что переместите свой звонок, чтобы начать в одном из этих двух мест, в зависимости от вашего желания. Основываясь на вашем комментарии, переместите вызов внутрь onWindowsFocusChanged().

ИЗМЕНИТЬ Итак, это "Как это сделать":

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    if(hasFocus){
        textView.startAnimation(AnimationUtils.loadAnimation(MainActivity.this,
            android.R.anim.slide_in_left|android.R.anim.fade_in));
    }   
}

Моменты, на которые стоит обратить внимание:

  • не забудьте написать случай if/else для проверки фокуса
  • и удалите автоматически сгенерированный "super.onWindowFocusChanged(hasFocus);"
person Kheldar    schedule 02.09.2011
comment
Это не удается: @Override public void onWindowFocusChanged (логическое значение hasFocus) { super.onWindowFocusChanged (hasFocus); animImg = (ImageView)findViewById(R.id.listen_anim); animImg.setBackgroundResource(R.drawable.listening); анимация = (AnimationDrawable) animImg.getBackground(); аним.старт(); }; - person hunterp; 03.09.2011
comment
Кроме того, будьте милы. Если я потрачу время на редактирование вашего вопроса и тегов, это будет в интересах других, которые могут совершить ту же ошибку. Как именно ваше переопределение терпит неудачу? - person Kheldar; 03.09.2011
comment
На основе учебника, опять же, я бы посоветовал вам поместить объявления внутри onCreate и только вызов для запуска внутри onWindowsFocusChanged - person Kheldar; 03.09.2011
comment
Что ж, если вас это устраивает, вы решили свою проблему. Запуск специальной ветки только для настройки анимации кажется мне немного чрезмерным, но у вас может быть веская причина, по которой вы воздерживаетесь. - person Kheldar; 03.09.2011
comment
Другого решения я не нашел, и во всех разговорах о stackoverflow и Android говорится, что требуется новый поток. - person hunterp; 03.09.2011
comment
Работает для меня и довольно прост в реализации. +1 - person SMBiggs; 12.02.2015
comment
Как насчет фрагмента? Во фрагменте нет onWindowFocusChanged(). - person Song; 16.01.2016
comment
Это не работает для меня, у кого-нибудь есть решение? - person Chris Rohit Brendan; 01.05.2016
comment
Если целевой объект анимации имеет тип EditText, как только вы нажмете на него, анимация снова перезапустится, есть идеи для этого? - person marticztn; 24.09.2020
comment
@MarticZtn Разве вы не можете использовать логический флаг? - person Kheldar; 24.09.2020
comment
@Khelmar Я понял это позже, я создал целое число, и оно будет увеличивать количество для каждого фокуса, затем я просто использовал оператор if, чтобы проверить, меньше или равно focusCount 1. - person marticztn; 25.09.2020

Установите флаг в onAttachedToWindow(), а затем в onWindowFocusChanged() проверьте его и запустите анимацию.

@Override
void onWindowFocusChanged(boolean hasFocus) {
    if (hasFocus & mbFlag) {
        // start animation.
    }
}

Обновлять

Просто расширьте класс ImageView и переопределите метод onFocusChange. Затем в своей деятельности установите на него фокус, вызвав animImg.requestFocus(). Анимация должна начаться, когда она сфокусируется. Убедитесь, что ваше изображение можно сфокусировать.

Если это не сработает, вы также можете переопределить метод onAttachedToWindow(). Установите там флажок и проверьте перед запуском анимации.

@Override
void onFocusChange(boolean hasFocus) {
    if (hasFocus) {
        // start animation.
    }
}
person Ronnie    schedule 03.09.2011
comment
какое представление onAttachedToWindow вы рекомендуете? - person hunterp; 05.09.2011
comment
Большое спасибо, это поможет мне. - person The iCoder; 03.11.2011

Вы можете использовать метод post любого View в действии. Вероятно, это должно выглядеть так:

View anyView = findViewById(R.id.anyView);
anyView.post(new Runnable()
{
    @Override
    public void run()
    {
        // Your code goes here
    }
});
person Muzikant    schedule 10.02.2013

Вам нужно дать время UI-менеджеру создать соответствующие ресурсы ДО запуска анимации. Правильный узор такой

a) Create animation object in onCreate.
b) Start animation object elsewhere.

Не создавайте и не запускайте одним и тем же методом.

person ruhalde    schedule 02.09.2011
comment
Да, ruhalde, см. наше обсуждение и его решение, где мы указали на это. - person Kheldar; 03.09.2011
comment
Хорошо, но никто не объясняет, почему вы должны делать это именно так. Все дело в однопоточной модели Android, в то время как ваш код выполняет диспетчер пользовательского интерфейса не работает, поэтому вы должны создать в OnCreate, а затем выйти (менеджер пользовательского интерфейса создает соответствующие ресурсы) и затем вы делаете Start() в своем коде и снова выходите (анимация статистики менеджера пользовательского интерфейса). - person ruhalde; 03.09.2011

Поскольку этот вопрос был задан некоторое время назад, я столкнулся с той же проблемой в 2019 году с использованием переходов-везде или переходов AndroidX. И единственным решением для меня было использовать ответ @Muzikant. Просто позвоните в свой onCreate()

rootViewOfYourLayout.post {
            TransitionManager.beginDelayedTransition(rootViewOfYourLayout)
            someViewId.visibility = View.VISIBLE
        }

И это отлично работает, например, в моем случае для заставки.

Обновление
После некоторого тестирования оказалось, что это решение имеет незначительную проблему. Анимация запускается, и вы блокируете телефон или перемещаете приложение в фоновый режим, и в результате, когда приложение снова находится на переднем плане, оно просто зависает, поскольку не получены обратные вызовы TransitionListener, поэтому в моем случае onTransitionEnd() не вызывался, где была расположена логика для перехода пользователя к следующий экран.

На данный момент это работает для меня без проблем:

  override fun onWindowFocusChanged(hasFocus: Boolean) {
   if(hasFocus && isAnimationStarted.not()){
   rootViewOfYourLayout.post {
          TransitionManager.beginDelayedTransition(rootViewOfYourLayout)
          someViewId.visibility = View.VISIBLE
            }
  }
}
person mr.kostua    schedule 16.08.2019

animation = AnimationUtils.loadAnimation(this, R.anim.push_left_out);

yourobject.startanimation(animation);

Это может помочь

person Sandip Lawate    schedule 30.07.2013

Запустите это в onResume():

class AnimTask extends AsyncTask<String, String,String> {
            Activity act;
            AnimTask(Activity act) {
                this.act = act;
            }

            @Override
            protected String doInBackground(String... params) {
                act.runOnUiThread(new Runnable() {
                    public void run(){
                        animImg = (ImageView)findViewById(R.id.listen_anim);
                        animImg.setBackgroundResource(R.drawable.listening);
                        anim = (AnimationDrawable) animImg.getBackground();
                        anim.start();
                    }
                });
                return null;
            }
        }
person hunterp    schedule 02.09.2011
comment
Кто бы -1 это лучше иметь объяснение - person hunterp; 03.09.2011
comment
Я не знаю, кто выразил это негативно, но у этого кода есть серьезные проблемы, вы НИКОГДА не обновляете объект пользовательского интерфейса вне потока пользовательского интерфейса. Убедитесь, что doInBackground() выполняется ВНЕШНИМ потоком пользовательского интерфейса. - person ruhalde; 03.09.2011
comment
Проблема, когда вы пытаетесь запустить поток непосредственно внутри действия, заключается в том, что он жалуется, что не запускается в потоке пользовательского интерфейса. Если вы просто попытаетесь запустить анимацию в onResume, ничего не произойдет, я полагаю, что немного чище будет создать Thread в onResume и вызвать Activity.this.runOnUiThread() , и поэтому я не верю, что вы правы, сэр. - person hunterp; 03.09.2011
comment
Дело в том, что этот код НЕВЕРНЫЙ, и вы плохо читаете документацию по Android. Stackoverflow — это не соревнование, кто что знает лучше, этот сайт предназначен для помощи другим, по крайней мере, так я его использую, и я многому здесь научился. Так что в следующий раз будьте более внимательны к людям, которые тратят свое драгоценное время, чтобы помочь вам. - person ruhalde; 03.09.2011
comment
Это работает, но это хакерское решение. Вы создаете состояние гонки, надеясь, что действие завершит настройку до запуска фонового потока. Он может работать на устройствах, но нет гарантии, что что-то не изменится в будущих версиях Android, а состояние гонки приведет к сбою. - person Gabriel; 17.01.2014
comment
Лучшей реализацией этого было бы опубликовать в представлении: myView.post(new Runnable() { ... }); - person Dallas; 02.05.2014