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

Flutter中ScaleTransition嵌套FadeTransition动画无法正常工作

问题分析与解决

你的动画失效问题核心在于快速点击按钮时,动画控制器的状态没有被正确处理——当动画还在执行过程中,重复调用forward()或reverse()会导致动画状态混乱,因为默认情况下动画控制器不会中断正在进行的动画,进而出现缩放动画失效、表现异常的情况。


解决思路

  1. 处理动画平滑过渡:在didUpdateWidget中,判断show状态变化时,使用animateTo()直接指定目标值(显示时到1.0,隐藏时到0.0),这样无论当前动画处于什么状态,都会平滑过渡到目标状态,避免状态冲突。
  2. 优化动画复用:由于缩放和淡入淡出动画的进度完全一致,可以复用同一个Animation对象,减少冗余代码。

修正后的代码

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: LogoScale(),
        ),
      ),
    );
  }
}

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

  @override
  State<LogoScale> createState() => LogoScaleState();
}

class LogoScaleState extends State<LogoScale> {
  bool show = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: (){
            setState(() {
              show = !show;
            });
          },
          child: Text(show ? 'Hide Logo' : 'Show Logo'),
        ),
        Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            AnimationInOut(
                show: show,
                child: const FlutterLogo(size: 100.0,)
            ),
          ],
        ),
      ],
    );
  }
}

class AnimationInOut extends StatefulWidget {
  final bool show;
  final Widget child;

  const AnimationInOut({super.key,
    required this.show,
    required this.child,
  });

  @override
  State<AnimationInOut> createState() => AnimationInOutState();
}

class AnimationInOutState extends State<AnimationInOut> with SingleTickerProviderStateMixin {

  late AnimationController animationController;
  late Animation<double> animation;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 300));
    // 初始化时设置对应状态的动画值
    animationController.value = widget.show ? 1.0 : 0.0;
    // 复用同一个动画给缩放和淡入淡出
    animation = animationController.drive(Tween<double>(begin: 0.0, end: 1.0));
  }

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

  @override
  void didUpdateWidget(AnimationInOut oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.show != oldWidget.show) {
      // 使用animateTo直接跳转到目标值,确保平滑过渡
      animationController.animateTo(
        widget.show ? 1.0 : 0.0,
        duration: const Duration(milliseconds: 300),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return ScaleTransition(
      scale: animation,
      child: FadeTransition(
        opacity: animation,
        child: widget.child,
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 16:26:03