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

Flutter如何实现容器从左到右的填充式颜色切换动画(仿Netflix“下一集”效果)

嘿,这个需求我刚好做过类似的!AnimatedContainer确实没法直接实现这种渐进式填充效果,但我们可以用Stack配合动画组件来搞定,完美还原Netflix“下一集”的那种左到右填充动画~

核心实现思路

用Stack将两个容器层叠:

  • 底层是你需要的初始色容器(比如白色),占满整个空间
  • 上层是目标色容器(比如红色),通过动画控制它的宽度从0过渡到容器的总宽度,视觉上就呈现出红色从左到右“填充”的效果
基础实现代码(简单版)

这个版本用AnimatedContainer就能快速实现,适合不需要复杂动画曲线的场景:

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

  @override
  State<FillAnimationContainer> createState() => _FillAnimationContainerState();
}

class _FillAnimationContainerState extends State<FillAnimationContainer> {
  // 控制红色填充的宽度,初始为0
  double _fillWidth = 0;
  // 动画时长,可根据需求调整
  final Duration _animationDuration = const Duration(seconds: 2);

  // 触发填充动画的方法
  void startFillAnimation() {
    setState(() {
      // 把宽度设为无限大,等同于占满底层容器
      _fillWidth = double.infinity;
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      // 点击触发动画,你也可以在页面加载时自动调用startFillAnimation()
      onTap: startFillAnimation,
      child: Container(
        width: 300,
        height: 60,
        // 外层容器加圆角,避免红色填充溢出
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey.shade300),
          borderRadius: BorderRadius.circular(8),
        ),
        child: Stack(
          children: [
            // 底层白色容器(初始底色)
            Container(
              width: double.infinity,
              height: double.infinity,
              color: Colors.white,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8),
              ),
            ),
            // 上层红色填充容器,用AnimatedContainer实现宽度动画
            AnimatedContainer(
              duration: _animationDuration,
              width: _fillWidth,
              color: Colors.red,
              // 和外层容器保持一致的圆角,只保留左侧圆角更自然
              decoration: const BoxDecoration(
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(8),
                  bottomLeft: Radius.circular(8),
                ),
              ),
            ),
            // 叠加文字(可选,模拟Netflix的"下一集"提示)
            const Center(
              child: Text(
                "下一集",
                style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
进阶实现(自定义动画曲线)

如果需要更贴合Netflix的缓入缓出动画效果,可以用AnimationController搭配CurvedAnimation来精细控制:

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

  @override
  State<AdvancedFillAnimation> createState() => _AdvancedFillAnimationState();
}

class _AdvancedFillAnimationState extends State<AdvancedFillAnimation> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _widthAnimation;
  final Duration _animationDuration = const Duration(seconds: 2);
  final double _containerWidth = 300;

  @override
  void initState() {
    super.initState();
    // 初始化动画控制器
    _controller = AnimationController(
      duration: _animationDuration,
      vsync: this,
    );
    // 设置动画曲线,Curves.easeInOut和Netflix的动画质感接近
    _widthAnimation = Tween<double>(begin: 0, end: _containerWidth).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );
  }

  @override
  void dispose() {
    // 记得销毁控制器,避免内存泄漏
    _controller.dispose();
    super.dispose();
  }

  void startFillAnimation() {
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: startFillAnimation,
      child: Container(
        width: _containerWidth,
        height: 60,
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey.shade300),
          borderRadius: BorderRadius.circular(8),
        ),
        child: Stack(
          children: [
            const Container(
              width: double.infinity,
              height: double.infinity,
              color: Colors.white,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(8)),
              ),
            ),
            // 用AnimatedBuilder监听动画值变化
            AnimatedBuilder(
              animation: _widthAnimation,
              builder: (context, child) {
                return Container(
                  width: _widthAnimation.value,
                  color: Colors.red,
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(8),
                      bottomLeft: Radius.circular(8),
                    ),
                  ),
                );
              },
            ),
            const Center(
              child: Text(
                "下一集",
                style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
关键细节提示
  • 如果需要圆角效果,务必让红色填充容器和外层容器的圆角保持一致,只保留左侧圆角会让填充动画更自然
  • 动画时长可以根据需求调整,Netflix的下一集动画大概在1.5-2秒左右
  • 可以通过_controller.reverse()实现反向填充动画,或者_controller.repeat()让动画循环播放

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:33:10