You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter多Tween自动循环动画实现:解决跳变问题

解决Flutter多属性自动循环Tween动画跳变问题

问题说明

需要实现容器的height、width、color三个属性自动循环平滑过渡的动画,但当前代码中容器属性直接取Tween的begin值,导致动画在随机值间跳变,无法实现平滑过渡效果。

错误原因

  1. 未利用AnimationController的进度值对Tween进行插值计算,直接使用Tween的begin属性,跳过了动画过渡过程
  2. 使用addListener判断动画完成状态,不如addStatusListener精准
  3. 未通过Tween的lerp方法根据动画进度获取当前过渡值

修正后的完整代码

import 'dart:math';
import 'package:flutter/material.dart';

class AnimatedSquare extends StatefulWidget {
  const AnimatedSquare({super.key});

  @override
  State<AnimatedSquare> createState() => _AnimatedSquareState();
}

class _AnimatedSquareState extends State<AnimatedSquare>
    with SingleTickerProviderStateMixin {
  late final AnimationController controller;
  late Tween<double> containerWidth;
  late Tween<double> containerHeight;
  late Tween<Color> containerColor;
  final Random random = Random();

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800),
    );

    // 初始化初始Tween值
    containerWidth = Tween<double>(
      begin: 250,
      end: random.nextInt(300).toDouble(),
    );
    containerHeight = Tween<double>(
      begin: 250,
      end: random.nextInt(300).toDouble(),
    );
    containerColor = Tween<Color>(
      begin: Colors.red,
      end: Color.fromRGBO(
        random.nextInt(255),
        random.nextInt(255),
        random.nextInt(255),
        1,
      ),
    );

    // 监听动画状态,完成后触发下一轮动画
    controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        setNewValues();
        controller.forward();
      }
    });

    controller.forward();
  }

  void setNewValues() {
    // 将当前结束值设为下一轮的起始值
    containerWidth.begin = containerWidth.end;
    containerHeight.begin = containerHeight.end;
    containerColor.begin = containerColor.end;

    // 重置控制器,准备新的动画
    controller.reset();

    // 设置新的随机结束值
    containerWidth.end = random.nextInt(300).toDouble();
    containerHeight.end = random.nextInt(300).toDouble();
    containerColor.end = Color.fromRGBO(
      random.nextInt(255),
      random.nextInt(255),
      random.nextInt(255),
      1,
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, child) {
        return Container(
          // 根据动画进度获取Tween插值后的当前值
          height: containerHeight.lerp(controller.value),
          width: containerWidth.lerp(controller.value),
          decoration: BoxDecoration(
            color: containerColor.lerp(controller.value),
          ),
        );
      },
    );
  }

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

关键修改点说明

  • 动画值计算:在AnimatedBuilder的builder方法中,使用Tween.lerp(controller.value)获取当前动画进度对应的属性值,实现平滑过渡
  • 状态监听优化:改用addStatusListener监听动画完成状态,比addListener更精准可靠
  • 初始化顺序调整:将super.initState()移到初始化控制器之前,符合Flutter生命周期规范
  • 代码规范:给Random变量添加final修饰符,提升代码可读性

内容的提问来源于stack exchange,提问作者Santiago G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:00:08