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
相关产品推荐
相关产品推荐

