Skip to content

Flutter 动画性能优化详解

简介

动画性能对用户体验有着重要影响。本文介绍如何优化 Flutter 动画性能,包括减少重建、使用 RepaintBoundary、优化动画曲线等方面。

基本原则

避免不必要的重建

dart
// 不推荐
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blue,
      child: ComplexWidget(), // 每次动画都会重建
    );
  },
);

// 推荐
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blue,
      child: child,
    );
  },
  child: ComplexWidget(), // 只构建一次
);

使用 RepaintBoundary

dart
class OptimizedAnimation extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: AnimatedWidget(),
    );
  }
}

性能监控

使用 Performance Overlay

dart
MaterialApp(
  showPerformanceOverlay: true,
  home: MyApp(),
);

检测帧率

dart
class PerformanceMonitor extends StatefulWidget {
  @override
  _PerformanceMonitorState createState() => _PerformanceMonitorState();
}

class _PerformanceMonitorState extends State<PerformanceMonitor> {
  late Stopwatch _stopwatch;
  late int _frameCount;
  late double _fps;

  @override
  void initState() {
    super.initState();
    _stopwatch = Stopwatch()..start();
    _frameCount = 0;
    _fps = 0;

    SchedulerBinding.instance.addPostFrameCallback(_onFrame);
  }

  void _onFrame(Duration timestamp) {
    _frameCount++;
    if (_stopwatch.elapsedMilliseconds > 1000) {
      _fps = _frameCount * 1000 / _stopwatch.elapsedMilliseconds;
      _frameCount = 0;
      _stopwatch.reset();
      _stopwatch.start();
      setState(() {});
    }
    SchedulerBinding.instance.addPostFrameCallback(_onFrame);
  }

  @override
  Widget build(BuildContext context) {
    return Text('FPS: ${_fps.toStringAsFixed(1)}');
  }
}

优化技巧

1. 使用 AnimatedWidget

dart
class OptimizedAnimatedWidget extends AnimatedWidget {
  OptimizedAnimatedWidget({
    Key? key,
    required Animation<double> animation,
  }) : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Transform.scale(
      scale: animation.value,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    );
  }
}

2. 分离动画逻辑

dart
class AnimationManager {
  final AnimationController controller;
  final Animation<double> scaleAnimation;
  final Animation<Color?> colorAnimation;

  AnimationManager({required TickerProvider vsync})
      : controller = AnimationController(
          duration: Duration(seconds: 1),
          vsync: vsync,
        ),
        scaleAnimation = Tween<double>(
          begin: 1.0,
          end: 2.0,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Curves.easeInOut,
        )),
        colorAnimation = ColorTween(
          begin: Colors.blue,
          end: Colors.red,
        ).animate(CurvedAnimation(
          parent: controller,
          curve: Curves.easeInOut,
        ));

  void dispose() {
    controller.dispose();
  }
}

3. 优化动画曲线

dart
// 避免复杂的自定义曲线
class SimpleCustomCurve extends Curve {
  @override
  double transform(double t) {
    return t * t; // 简单的平方曲线
  }
}

完整示例

dart
class OptimizedAnimationDemo extends StatefulWidget {
  @override
  _OptimizedAnimationDemoState createState() => _OptimizedAnimationDemoState();
}

class _OptimizedAnimationDemoState extends State<OptimizedAnimationDemo>
    with SingleTickerProviderStateMixin {
  late AnimationManager _animationManager;
  final int itemCount = 100;

  @override
  void initState() {
    super.initState();
    _animationManager = AnimationManager(vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Optimized Animation'),
        actions: [
          PerformanceMonitor(),
        ],
      ),
      body: RepaintBoundary(
        child: ListView.builder(
          itemCount: itemCount,
          itemBuilder: (context, index) {
            // 使用不同的延迟创建交错动画
            final delay = index / itemCount;
            final delayedAnimation = CurvedAnimation(
              parent: _animationManager.controller,
              curve: Interval(
                delay,
                delay + 0.5,
                curve: Curves.easeInOut,
              ),
            );

            return RepaintBoundary(
              child: OptimizedAnimatedWidget(
                animation: delayedAnimation,
              ),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_animationManager.controller.status == 
              AnimationStatus.completed) {
            _animationManager.controller.reverse();
          } else {
            _animationManager.controller.forward();
          }
        },
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

最佳实践

  1. 使用 RepaintBoundary 隔离动画区域
  2. 避免在动画过程中进行复杂计算
  3. 优化动画组件的重建
  4. 合理使用缓存
  5. 监控动画性能

注意事项

  1. 不要过度使用 RepaintBoundary
  2. 避免在动画中加载大图片
  3. 注意内存使用
  4. 处理好动画的生命周期
  5. 在低端设备上进行测试

总结

通过合理的性能优化,可以显著提升动画的流畅度和用户体验。掌握这些优化技巧对于开发高质量的 Flutter 应用至关重要。