← Назад к вопросам

В каком методе Activity лучше всего запустить анимацию

2.3 Middle🔥 121 комментариев
#UI и вёрстка#Жизненный цикл и навигация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оптимальное место для запуска анимации в Activity

Лучшим методом для запуска большинства анимаций в Activity является onWindowFocusChanged(boolean hasFocus), особенно когда анимация зависит от размеров или видимости UI-компонентов после полной инициализации макета. Это обусловлено жизненным циклом Activity и этапами отрисовки представлений.

Почему onWindowFocusChanged?

Ключевая причина — гарантия, что иерархия View полностью готова к измерению и отрисовке. На момент вызова onCreate(), onStart() или даже onResume() представления могут ещё не иметь рассчитанных размеров (ширины/высоты), так как фаза layout происходит позже. Запуск анимации, зависящей от размеров (например, движение от края экрана), в этих методах приведёт к нулевым значениям getWidth() или getHeight().

Метод onWindowFocusChanged() вызывается, когда окно Activity получает или теряет фокус ввода. При первом вызове с hasFocus = true это сигнализирует, что:

  • Активность видима и взаимодействует с пользователем.
  • Все view измерены, размещены и готовы к отображению.
  • Можно безопасно получать актуальные геометрические параметры виджетов.

Пример использования

class MainActivity : AppCompatActivity() {

    private lateinit var animatedView: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        animatedView = findViewById(R.id.my_view)
        // Не запускаем анимацию здесь — размеры view ещё не известны
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus) {
            // Теперь размеры view точно доступны
            startViewAnimation()
        }
    }

    private fun startViewAnimation() {
        val screenWidth = Resources.getSystem().displayMetrics.widthPixels
        val translateAnim = ObjectAnimator.ofFloat(
            animatedView, 
            "translationX", 
            screenWidth.toFloat(), 
            0f
        )
        translateAnim.duration = 1000
        translateAnim.start()
    }
}

Альтернативные подходы

Хотя onWindowFocusChanged() — наиболее надёжный вариант, в некоторых сценариях можно использовать другие методы:

  1. Использование View.post(Runnable) в onResume():
    override fun onResume() {
        super.onResume()
        animatedView.post {
            // Этот код выполнится после layout-пасса
            startViewAnimation()
        }
    }
    
    Это хорошая альтернатива, так как `Runnable` выполняется в следующем цикле обработки сообщений, когда view уже размещены.

  1. Слушатель глобального layout (ViewTreeObserver):
    animatedView.viewTreeObserver.addOnGlobalLayoutListener(
        object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                animatedView.viewTreeObserver.removeOnGlobalLayoutListener(this)
                startViewAnimation()
            }
        }
    )
    
    Полезно, если нужно отреагировать именно на момент завершения компоновки, но более многословно.

Рекомендации по типам анимаций

  • Запуск анимаций при старте активности (входные переходы, fade-in, слайды) — используйте onWindowFocusChanged() или View.post() в onResume().
  • Анимации, инициированные пользовательским взаимодействием (клики, свайпы) — запускайте непосредственно в обработчиках событий (onClick, onTouch).
  • Анимации, не зависящие от размеров view (например, простые повороты или альфа-анимации заранее известных элементов) — можно запускать в onResume().
  • Анимации с использованием Window Animations (transition между активити) — настраивайте через overridePendingTransition() сразу после startActivity() или finish().

Важные нюансы

  • Повторный запуск: onWindowFocusChanged() вызывается при каждом получении/потере фокуса (сворачивание/разворачивание приложения, появление диалога). Добавляйте флаги, чтобы предотвратить повторный запуск анимации.
  • Производительность: Сложные анимации на многих элементах могут вызывать просадки FPS. Используйте Hardware Acceleration и оптимизированные аниматоры (ObjectAnimator, ValueAnimator).
  • Жизненный цикл: Всегда останавливайте анимации в onPause() или onStop(), чтобы избежать утечек ресурсов и исключений при обращении к уничтоженным view.

Таким образом, для большинства сценариев стартовой анимации onWindowFocusChanged() с проверкой hasFocus является оптимальным выбором, обеспечивающим корректную работу с геометрией view и предсказуемое поведение. Для простых случаев достаточно View.post() в onResume() как более лаконичной альтернативы.

В каком методе Activity лучше всего запустить анимацию | PrepBro