Расскажи про анимации в Flutter.

«Расскажи про анимации в Flutter.» — вопрос из категории Анимации, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Flutter предоставляет мощную и гибкую систему анимаций, которая делится на два основных типа: неявные (implicit) и явные (explicit). Все анимации работают на 60/120 FPS благодаря движку Skia.

1. Неявные анимации (Implicit Animations)

Самый простой способ. Используются специальные виджеты (с префиксом Animated...), которые автоматически анимируют изменения своих свойств.

bool _selected = false;

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () => setState(() => _selected = !_selected),
    child: AnimatedContainer(
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut, // Кривая для естественного движения.
      width: _selected ? 200 : 100,
      height: _selected ? 200 : 100,
      color: _selected ? Colors.blue : Colors.grey,
      child: Center(child: Text('Tap me')),
    ),
  );
}

Другие примеры: AnimatedOpacity, AnimatedPadding, AnimatedAlign.

2. Явные анимации (Explicit Animations)

Дают полный контроль над анимацией через AnimationController. Используются для сложных, составных или повторяющихся анимаций.

class _RotationAnimation extends StatefulWidget {
  @override
  _RotationAnimationState createState() => _RotationAnimationState();
}

class _RotationAnimationState extends State<_RotationAnimation>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    // Контроллер управляет временем анимации (vsync синхронизирует с частотой кадров).
    _controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    );
    // Tween определяет диапазон значений анимации.
    _animation = Tween<double>(begin: 0, end: 2 * pi).animate(_controller);
    _controller.repeat(); // Запускаем анимацию на повтор.
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Transform.rotate(
          angle: _animation.value,
          child: FlutterLogo(size: 100),
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // Важно: всегда освобождаем контроллер.
    super.dispose();
  }
}

3. Анимации на основе физики (Physics-based)

Имитируют реальное движение (пружины, гравитация) через SpringSimulation, GravitySimulation.

4. Hero-анимации

Для плавного перехода виджета между экранами (навигации).

// На первом экране
Hero(
  tag: 'avatar', // Уникальный тег.
  child: CircleAvatar(backgroundImage: NetworkImage(url)),
)

// На втором экране используем виджет с тем же тегом.
Hero(
  tag: 'avatar',
  child: Image.network(url, fit: BoxFit.cover),
)

5. Интеграция с Rive/Lottie

Для сложных векторных анимаций, созданных дизайнерами, используется пакет rive или lottie. Это позволяет загружать готовые анимации из Figma или After Effects.

Ключевой принцип: В Flutter анимация — это просто интерполяция значений (числа, цвета и т.д.) во времени, управляемая Animation объектами. Виджеты перерисовываются на каждом кадре с новым значением, создавая иллюзию движения.