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

Flutter中如何为AnimatedOpacity/AnimatedContainer动画设置延迟

Flutter 官方提供的 AnimatedOpacity 没有内置延迟启动的参数,要实现单向动画触发延迟,可选用以下两种方案:

方案1:状态触发时加延迟控制

这是改造成本最低的方案,仅需调整 _reduced 变量的更新逻辑即可:

  • 当需要触发透明度从0到1的动画(也就是把 _reduced 从true改为false)时,加500ms延迟再更新状态
  • 反向触发(_reduced 从false改为true)时直接更新状态

代码示例:

// 存储延迟任务,避免快速切换时状态混乱
Timer? _delayTimer;

// 触发显示动画(透明度从0变1)
void _triggerShow() {
  _delayTimer?.cancel();
  _delayTimer = Timer(const Duration(milliseconds: 500), () {
    if (!mounted) return;
    setState(() => _reduced = false);
  });
}

// 触发隐藏动画(透明度从1变0)
void _triggerHide() {
  _delayTimer?.cancel();
  if (!mounted) return;
  setState(() => _reduced = true);
}

对应的 AnimatedOpacity 就可以统一设置动画时长为120ms:

AnimatedOpacity(
  duration: const Duration(milliseconds: 120),
  opacity: _reduced ? 0 : 1,
  child: const Text('hi di hi'),
)

方案2:封装带方向延迟的自定义动画组件

如果希望延迟逻辑和动画组件绑定,无需修改外部状态触发逻辑,可以自定义隐式动画组件:

import 'package:flutter/material.dart';

class DirectionalDelayedAnimatedOpacity extends ImplicitlyAnimatedWidget {
  final double opacity;
  final Widget child;
  /// 透明度升高方向动画的启动延迟
  final Duration forwardDelay;

  const DirectionalDelayedAnimatedOpacity({
    super.key,
    required this.opacity,
    required this.child,
    required super.duration,
    this.forwardDelay = Duration.zero,
    super.curve = Curves.linear,
  });

  @override
  ImplicitlyAnimatedWidgetState<DirectionalDelayedAnimatedOpacity> createState() => _DirectionalDelayedAnimatedOpacityState();
}

class _DirectionalDelayedAnimatedOpacityState extends ImplicitlyAnimatedWidgetState<DirectionalDelayedAnimatedOpacity> {
  Tween<double>? _opacityTween;
  late Animation<double> _opacityAnimation;

  @override
  void forEachTween(TweenVisitor<dynamic> visitor) {
    _opacityTween = visitor(
      _opacityTween,
      widget.opacity,
      (value) => Tween<double>(begin: value as double),
    ) as Tween<double>;
  }

  @override
  void didUpdateTweens() {
    final isForwardAnimation = _opacityTween?.end ?? 0 > _opacityTween?.begin ?? 0;
    if (isForwardAnimation && widget.forwardDelay != Duration.zero) {
      // 正向动画通过Interval插入延迟时长
      final totalMilliseconds = widget.duration.inMilliseconds + widget.forwardDelay.inMilliseconds;
      final delayInterval = widget.forwardDelay.inMilliseconds / totalMilliseconds;
      animation = CurvedAnimation(
        parent: controller.drive(
          Tween(begin: 0.0, end: 1.0).chain(
            CurveTween(curve: Interval(delayInterval, 1.0)),
          ),
        ),
        curve: widget.curve,
      );
    } else {
      animation = CurvedAnimation(parent: controller, curve: widget.curve);
    }
    _opacityAnimation = _opacityTween!.animate(animation);
  }

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

使用方式完全符合你期望的调用习惯:

DirectionalDelayedAnimatedOpacity(
  duration: const Duration(milliseconds: 120),
  forwardDelay: _reduced ? Duration.zero : const Duration(milliseconds: 500),
  opacity: _reduced ? 0 : 1,
  child: const Text('hi di hi'),
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 13:09:02