公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

Flutter 交错动画详解

简介

交错动画是指多个动画按照一定的时间间隔依次播放的动画效果。通过合理设置动画的延迟和间隔,可以创建出富有层次感的动画效果。

基本用法

使用 Interval

dart
class StaggeredAnimationDemo extends StatefulWidget {
  @override
  _StaggeredAnimationDemoState createState() => _StaggeredAnimationDemoState();
}

class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _opacity;
  late Animation<double> _width;
  late Animation<double> _height;
  late Animation<EdgeInsets> _padding;
  late Animation<BorderRadius?> _borderRadius;
  late Animation<Color?> _color;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 2000),
      vsync: this,
    );

    _opacity = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.0, 0.2, curve: Curves.ease),
    ));

    _width = Tween<double>(
      begin: 50.0,
      end: 200.0,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.2, 0.4, curve: Curves.ease),
    ));

    _height = Tween<double>(
      begin: 50.0,
      end: 200.0,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.4, 0.6, curve: Curves.ease),
    ));

    _padding = EdgeInsetsTween(
      begin: EdgeInsets.only(bottom: 16.0),
      end: EdgeInsets.only(bottom: 75.0),
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.6, 0.8, curve: Curves.ease),
    ));

    _borderRadius = BorderRadiusTween(
      begin: BorderRadius.circular(4.0),
      end: BorderRadius.circular(75.0),
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.8, 1.0, curve: Curves.ease),
    ));

    _color = ColorTween(
      begin: Colors.blue,
      end: Colors.purple,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.8, 1.0, curve: Curves.ease),
    ));
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Staggered Animation')),
      body: GestureDetector(
        onTap: () {
          if (_controller.status == AnimationStatus.completed) {
            _controller.reverse();
          } else {
            _controller.forward();
          }
        },
        child: Center(
          child: AnimatedBuilder(
            animation: _controller,
            builder: (context, child) {
              return Container(
                padding: _padding.value,
                alignment: Alignment.bottomCenter,
                child: Opacity(
                  opacity: _opacity.value,
                  child: Container(
                    width: _width.value,
                    height: _height.value,
                    decoration: BoxDecoration(
                      color: _color.value,
                      borderRadius: _borderRadius.value,
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

列表交错动画

基本实现

dart
class StaggeredListDemo extends StatefulWidget {
  @override
  _StaggeredListDemoState createState() => _StaggeredListDemoState();
}

class _StaggeredListDemoState extends State<StaggeredListDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  final List<String> _items = List.generate(20, (i) => 'Item $i');

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 1000),
      vsync: this,
    );
    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _items.length,
      itemBuilder: (context, index) {
        return AnimatedBuilder(
          animation: _controller,
          builder: (context, child) {
            final delay = index * 0.1;
            final animation = CurvedAnimation(
              parent: _controller,
              curve: Interval(
                delay.clamp(0.0, 1.0),
                (delay + 0.1).clamp(0.0, 1.0),
                curve: Curves.easeOut,
              ),
            );

            return SlideTransition(
              position: Tween<Offset>(
                begin: Offset(1.0, 0.0),
                end: Offset.zero,
              ).animate(animation),
              child: FadeTransition(
                opacity: animation,
                child: child,
              ),
            );
          },
          child: ListTile(
            title: Text(_items[index]),
          ),
        );
      },
    );
  }
}

高级用法

组合动画

dart
class CombinedStaggeredAnimation extends StatelessWidget {
  final Animation<double> controller;
  final Animation<double> opacity;
  final Animation<double> dx;
  final Animation<double> dy;
  final Animation<Color?> color;

  CombinedStaggeredAnimation({required this.controller})
      : opacity = Tween<double>(
          begin: 0.0,
          end: 1.0,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Interval(0.0, 0.3, curve: Curves.ease),
        )),
        dx = Tween<double>(
          begin: -100.0,
          end: 0.0,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Interval(0.3, 0.6, curve: Curves.ease),
        )),
        dy = Tween<double>(
          begin: -50.0,
          end: 0.0,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Interval(0.6, 0.9, curve: Curves.ease),
        )),
        color = ColorTween(
          begin: Colors.blue,
          end: Colors.purple,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Interval(0.9, 1.0, curve: Curves.ease),
        ));

  Widget _buildAnimation(BuildContext context, Widget? child) {
    return Transform.translate(
      offset: Offset(dx.value, dy.value),
      child: Opacity(
        opacity: opacity.value,
        child: Container(
          width: 100,
          height: 100,
          decoration: BoxDecoration(
            color: color.value,
            borderRadius: BorderRadius.circular(10),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      builder: _buildAnimation,
      animation: controller,
    );
  }
}

最佳实践

  1. 合理设置动画间隔
  2. 使用适当的动画曲线
  3. 避免过多的交错动画
  4. 注意性能影响
  5. 合理组织动画代码

注意事项

  1. 避免动画间隔过短
  2. 注意内存管理
  3. 处理好动画状态
  4. 合理设置动画时长
  5. 避免过度使用动画

总结

交错动画可以创建出富有层次感和韵律感的动画效果,通过合理使用可以显著提升应用的用户体验。理解并掌握交错动画的使用对于开发高质量的 Flutter 应用很有帮助。