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

如何为从Widget树移除的Row子组件添加动画效果?

解决方案

原生实现(无第三方包)

直接用Flutter自带的动画组件和控制器,就能实现需求的两种动画效果。核心思路是让Widget1在动画过程中保持在Widget树中,完成动画后再移除,同时联动Widget2的位置和大小变化。

步骤1:初始化动画控制器和动画对象

在State类中定义动画相关变量:

late AnimationController _animController;
late Animation<double> _fadeAnim; // Widget1的淡出动画
late Animation<double> _slideAnim; // Widget2的平移动画
late Animation<double> _scaleAnim; // Widget2的缩放动画

@override
void initState() {
  super.initState();
  // 统一设置动画时长为300ms
  _animController = AnimationController(
    duration: const Duration(milliseconds: 300),
    vsync: this,
  );
  
  // 配置Widget1的淡出动画:从完全显示到透明
  _fadeAnim = Tween<double>(begin: 1.0, end: 0.0).animate(
    CurvedAnimation(parent: _animController, curve: Curves.easeOut),
  );
  
  // 配置Widget2的平移动画:假设Widget1宽度为100,向左平移100像素
  _slideAnim = Tween<double>(begin: 0.0, end: -100.0).animate(
    CurvedAnimation(parent: _animController, curve: Curves.easeOut),
  );
  
  // 配置Widget2的缩放动画:从原大小放大到1.2倍
  _scaleAnim = Tween<double>(begin: 1.0, end: 1.2).animate(
    CurvedAnimation(parent: _animController, curve: Curves.easeOut),
  );
}

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

步骤2:处理状态切换的触发逻辑

写一个方法来切换condition并触发/反向动画:

void toggleCondition() {
  setState(() {
    condition = !condition;
  });
  // 当condition变为false时播放退出动画,变为true时反向播放恢复动画
  condition ? _animController.reverse() : _animController.forward();
}

步骤3:构建带动画的UI

修改buildUI方法,用动画组件包裹目标Widget:

Widget buildUI() {
  return Row(
    children: [
      // 动画过程中Widget1保持在树中,完成后移除
      if (condition || _animController.isAnimating)
        FadeTransition(
          opacity: _fadeAnim,
          child: SizeTransition(
            sizeFactor: _fadeAnim,
            axis: Axis.horizontal,
            child: Widget1(),
          ),
        ),
      // 用AnimatedBuilder联动Widget2的动画
      AnimatedBuilder(
        animation: _animController,
        builder: (context, child) {
          return Transform(
            transform: Matrix4.translationValues(
              _slideAnim.value,
              0.0,
              0.0,
            )..scale(_scaleAnim.value),
            alignment: Alignment.centerLeft,
            child: child,
          );
        },
        child: Widget2(),
      ),
    ],
  );
}

第三方包简化实现

如果觉得原生代码繁琐,可以用animated_widgets包,它封装了常用的动画组件,减少重复代码。

步骤1:添加依赖

在pubspec.yaml中添加:

dependencies:
  animated_widgets: ^1.1.0

步骤2:构建动画UI

直接用包提供的组件包裹Widget即可:

bool condition = true;

void toggleCondition() {
  setState(() {
    condition = !condition;
  });
}

Widget buildUI() {
  return Row(
    children: [
      if (condition)
        FadeAnimatedWidget(
          duration: const Duration(milliseconds: 300),
          enabled: !condition,
          child: SizeAnimatedWidget(
            duration: const Duration(milliseconds: 300),
            enabled: !condition,
            axis: Axis.horizontal,
            child: Widget1(),
          ),
        ),
      SlideAnimatedWidget(
        duration: const Duration(milliseconds: 300),
        enabled: !condition,
        animationType: AnimationType.slideLeft,
        child: ScaleAnimatedWidget(
          duration: const Duration(milliseconds: 300),
          enabled: !condition,
          scale: 1.2,
          child: Widget2(),
        ),
      ),
    ],
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:52:47