公告

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

Skip to content

Flutter 渲染优化详解

简介

渲染性能直接影响应用的流畅度。本文介绍如何优化 Flutter 应用的渲染性能。

基本概念

渲染流程

  1. Layout - 计算大小和位置
  2. Paint - 绘制界面
  3. Composite - 合成图层

性能指标

  1. 帧率(FPS)
  2. 帧时间
  3. 掉帧数量

优化方法

1. 减少重建

dart
// 使用 const 构造函数
const MyWidget(
  key: Key('my_widget'),
  title: 'Hello',
);

// 使用 StatelessWidget
class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Hello'),
    );
  }
}

2. 使用 RepaintBoundary

dart
class OptimizedList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100,
      itemBuilder: (context, index) {
        return RepaintBoundary(
          child: ListItem(index: index),
        );
      },
    );
  }
}

3. 图层优化

dart
// 避免不必要的 Opacity
// 不推荐
Opacity(
  opacity: 0.5,
  child: ExpensiveWidget(),
);

// 推荐
Container(
  color: Colors.black.withOpacity(0.5),
  child: ExpensiveWidget(),
);

// 使用 Transform 代替 Positioned
// 不推荐
Stack(
  children: [
    Positioned(
      left: _animation.value,
      child: ExpensiveWidget(),
    ),
  ],
);

// 推荐
Transform.translate(
  offset: Offset(_animation.value, 0),
  child: ExpensiveWidget(),
)

完整示例

dart
class RenderOptimizedApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: OptimizedList(),
      ),
    );
  }
}

class OptimizedList extends StatefulWidget {
  @override
  _OptimizedListState createState() => _OptimizedListState();
}

class _OptimizedListState extends State<OptimizedList> {
  final ScrollController _controller = ScrollController();
  final List<String> _items = List.generate(1000, (i) => 'Item $i');
  
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      controller: _controller,
      cacheExtent: 100, // 缓存范围
      physics: const BouncingScrollPhysics(),
      slivers: [
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              // 使用 RepaintBoundary 隔离重绘区域
              return RepaintBoundary(
                child: _buildItem(index),
              );
            },
            childCount: _items.length,
          ),
        ),
      ],
    );
  }
  
  Widget _buildItem(int index) {
    // 使用 const 构造函数
    return const ListItemWidget(
      height: 100,
      margin: EdgeInsets.symmetric(
        horizontal: 16,
        vertical: 8,
      ),
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

class ListItemWidget extends StatelessWidget {
  final double height;
  final EdgeInsets margin;
  
  const ListItemWidget({
    Key? key,
    required this.height,
    required this.margin,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Container(
      height: height,
      margin: margin,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: const [
          BoxShadow(
            color: Colors.black12,
            offset: Offset(0, 2),
            blurRadius: 4,
          ),
        ],
      ),
      child: const _ItemContent(),
    );
  }
}

class _ItemContent extends StatelessWidget {
  const _ItemContent({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Row(
      children: const [
        _ItemImage(),
        SizedBox(width: 16),
        Expanded(child: _ItemText()),
      ],
    );
  }
}

性能监控

1. 性能叠加层

dart
void main() {
  runApp(
    Directionality(
      textDirection: TextDirection.ltr,
      child: Stack(
        children: [
          MyApp(),
          const PerformanceOverlay.allEnabled(),
        ],
      ),
    ),
  );
}

2. 自定义性能监控

dart
class PerformanceMonitor {
  static final stopwatch = Stopwatch();
  static int _frameCount = 0;
  static double _fps = 0;
  
  static void startMonitoring() {
    stopwatch.start();
    SchedulerBinding.instance.addPostFrameCallback(_onFrame);
  }
  
  static void _onFrame(Duration timestamp) {
    _frameCount++;
    if (stopwatch.elapsedMilliseconds >= 1000) {
      _fps = _frameCount * 1000 / stopwatch.elapsedMilliseconds;
      print('FPS: ${_fps.toStringAsFixed(1)}');
      _frameCount = 0;
      stopwatch.reset();
      stopwatch.start();
    }
    SchedulerBinding.instance.addPostFrameCallback(_onFrame);
  }
}

最佳实践

  1. 使用 const 构造函数
  2. 合理使用 RepaintBoundary
  3. 优化图层结构
  4. 避免不必要的重建
  5. 监控渲染性能

注意事项

  1. 避免过度优化
  2. 平衡性能和代码可读性
  3. 注意内存占用
  4. 测试不同设备
  5. 监控性能指标

总结

渲染优化需要从多个层面入手,包括减少重建、优化图层、合理使用缓存等。通过合理的优化措施,可以显著提升应用的渲染性能和流畅度。