Что такое Tween в анимациях Flutter?

Ответ

Tween (от in-between) — это объект, который интерполирует (вычисляет промежуточные значения) между начальным (begin) и конечным (end) значением за время анимации. Это ядро для создания плавных переходов не только чисел, но и цветов, размеров, положений и даже пользовательских типов.

Основная концепция: Tween сам по себе не анимирует. Он определяет диапазон значений. Анимация создается при связывании Tween с AnimationController через метод .animate().

Пример анимации изменения размера и цвета контейнера:

class AnimatedBox extends StatefulWidget {
  @override
  _AnimatedBoxState createState() => _AnimatedBoxState();
}

class _AnimatedBoxState extends State<AnimatedBox> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _sizeAnimation;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true); // Бесконечная анимация туда-обратно

    // Tween для размера от 50 до 200 пикселей
    _sizeAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);
    // Tween для цвета от синего до красного
    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Container(
          width: _sizeAnimation.value,
          height: _sizeAnimation.value,
          color: _colorAnimation.value,
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

Встроенные и специализированные Tween-классы:

  • ColorTween: Интерполяция цветов.
  • SizeTween: Интерполяция размеров (Size).
  • RectTween: Интерполяция прямоугольников (Rect).
  • BorderRadiusTween: Интерполяция скругления углов.
  • AlignmentTween, EdgeInsetsTween и многие другие.

Для сложных последовательностей используйте TweenSequence:

final animation = TweenSequence<double>([
  TweenSequenceItem(tween: Tween(begin: 0.0, end: 100.0), weight: 50.0),
  TweenSequenceItem(tween: Tween(begin: 100.0, end: 50.0), weight: 50.0),
]).animate(_controller);

Ответ 18+ 🔞

А, ну это ж про твины в Flutter! Слушай, тут всё просто, как три копейки, но если не вникнуть — можно охуеть от непонимания.

Представь себе, что твин — это такой хитрая жопа, которая знает, как плавно перетечь из точки А в точку Б. Не просто прыгнуть, а именно проехаться по всем промежуточным значениям. Начало есть, конец есть, а между ними — целая куча рассчитанных шагов.

Но вот в чём прикол: сам по себе твин нихуя не двигается. Это просто формула, план. Чтобы он ожил, его надо скормить AnimationController через метод .animate(). Вот тогда и начинается магия.

Смотри, как это выглядит на практике — делаем квадратик, который пульсирует и меняет цвет:

class AnimatedBox extends StatefulWidget {
  @override
  _AnimatedBoxState createState() => _AnimatedBoxState();
}

class _AnimatedBoxState extends State<AnimatedBox> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _sizeAnimation;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true); // Гоняем туда-сюда бесконечно

    // Вот он, твин для размера. Сказали: начни с 50, закончи на 200.
    _sizeAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);
    // А это твин для цвета. Из синего в красный.
    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Container(
          width: _sizeAnimation.value, // Берём текущее значение из твина
          height: _sizeAnimation.value,
          color: _colorAnimation.value,
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // Не забываем почистить за собой, а то будет утечка
    super.dispose();
  }
}

Ну и, ёпта, фреймворк не дурак — там уже куча готовых твинов на все случаи жизни. Не надо изобретать велосипед, чтобы цвет поменять или угол скруглить.

  • ColorTween — для цветов.
  • SizeTween — для размеров.
  • RectTween — для прямоугольников.
  • BorderRadiusTween — чтобы углы скруглялись плавно.
  • AlignmentTween, EdgeInsetsTween — и ещё овердохуища других.

А если тебе надо не просто из А в Б, а сделать сложную траекторию — типа увеличился, потом подпрыгнул, потом съёжился — тогда тебе в помощь TweenSequence. Туда запихиваешь куски анимации, как пазл:

final animation = TweenSequence<double>([
  TweenSequenceItem(tween: Tween(begin: 0.0, end: 100.0), weight: 50.0), // Первый отрезок
  TweenSequenceItem(tween: Tween(begin: 100.0, end: 50.0), weight: 50.0), // Второй отрезок
]).animate(_controller);

В общем, инструмент мощный. Главное — понять, что твин это не анимация, а её описание. А оживляет всё контроллер. Как только это щёлкнет в голове — всё остальное уже дело техники и фантазии.