Flutter CustomPaint 完全解析CustomPaint是 Flutter 中用于自定义绘制的核心组件它允许你通过代码直接在画布上绘制图形、文字、路径等实现各种自定义的 UI 效果比如图表、自定义形状、手绘效果等。一、核心概念与基础用法1. 核心组件CustomPaint承载绘制内容的容器CustomPainter绘制逻辑的核心类需要继承并实现paint和shouldRepaint方法Canvas画布提供各种绘制方法画圆、画线、画路径等Size绘制区域的尺寸2. 基础示例绘制一个带边框的圆形dartimport package:flutter/material.dart; void main() runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text(CustomPaint 示例)), body: Center( // 核心容器CustomPaint child: CustomPaint( size: const Size(200, 200), // 绘制区域大小 painter: MyCustomPainter(), // 自定义绘制逻辑 ), ), ), ); } } // 自定义绘制类继承 CustomPainter class MyCustomPainter extends CustomPainter { override void paint(Canvas canvas, Size size) { // 1. 创建画笔设置颜色、宽度、样式等 final paint Paint() ..color Colors.blue // 填充色 ..style PaintingStyle.fill; // 填充模式stroke 为描边 // 2. 绘制圆形圆心在画布中心半径为画布宽度的一半 canvas.drawCircle( Offset(size.width / 2, size.height / 2), // 圆心坐标 size.width / 2, // 半径 paint, // 画笔 ); // 3. 绘制边框重新设置画笔样式 final borderPaint Paint() ..color Colors.red ..style PaintingStyle.stroke ..strokeWidth 4; // 描边宽度 canvas.drawCircle( Offset(size.width / 2, size.height / 2), size.width / 2, borderPaint, ); } // 决定是否需要重绘true重绘false不重绘 override bool shouldRepaint(covariant CustomPainter oldDelegate) { // 简单场景直接返回 false无状态绘制 // 有状态时对比新旧数据数据变化返回 true return false; } }二、常用绘制方法Canvas提供了丰富的绘制 API以下是最常用的表格方法功能示例drawCircle绘制圆形canvas.drawCircle(Offset(100,100), 50, paint)drawRect绘制矩形canvas.drawRect(Rect.fromLTWH(50,50,100,80), paint)drawLine绘制直线canvas.drawLine(Offset(0,0), Offset(200,200), paint)drawPath绘制自定义路径见下文示例drawText绘制文字需配合 TextPainter见下文示例示例 1绘制自定义路径三角形dartoverride void paint(Canvas canvas, Size size) { final paint Paint() ..color Colors.green ..style PaintingStyle.fill; // 创建路径 final path Path() ..moveTo(size.width / 2, 0) // 起点顶部 ..lineTo(0, size.height) // 连线到左下角 ..lineTo(size.width, size.height) // 连线到右下角 ..close(); // 闭合路径回到起点 canvas.drawPath(path, paint); }示例 2绘制文字dartoverride void paint(Canvas canvas, Size size) { // 创建 TextPainter final textPainter TextPainter( text: const TextSpan( text: 自定义文字, style: TextStyle(color: Colors.black, fontSize: 24), ), textDirection: TextDirection.ltr, ); // 布局文字计算尺寸 textPainter.layout(); // 绘制文字居中显示 textPainter.paint( canvas, Offset( (size.width - textPainter.width) / 2, (size.height - textPainter.height) / 2, ), ); }三、进阶技巧1. 有状态绘制动态更新如果需要根据数据动态更新绘制内容需在CustomPainter中接收数据参数shouldRepaint对比新旧数据变化时返回true示例dartclass DynamicPainter extends CustomPainter { final double progress; // 动态参数比如进度值 0-1 DynamicPainter({required this.progress}); override void paint(Canvas canvas, Size size) { final paint Paint()..color Colors.orange; // 绘制进度条宽度随 progress 变化 canvas.drawRect( Rect.fromLTWH(0, 0, size.width * progress, size.height), paint, ); } override bool shouldRepaint(DynamicPainter oldDelegate) { // 对比进度值变化则重绘 return oldDelegate.progress ! progress; } } // 使用时通过 setState 更新 // setState(() _progress 0.1); // CustomPaint(painter: DynamicPainter(progress: _progress))2. 叠加绘制foregroundPainterCustomPaint提供foregroundPainter参数可在子组件上层绘制dartCustomPaint( size: const Size(200, 200), painter: MyBackgroundPainter(), // 底层绘制 foregroundPainter: MyForegroundPainter(), // 上层绘制 child: const Center(child: Text(子组件)), // 中间的子组件 )3. 性能优化避免在paint方法中创建对象比如Paint、Path建议提前初始化shouldRepaint尽量精准避免不必要的重绘复杂绘制可使用RepaintBoundary隔离重绘区域四、前置条件使用CustomPaint无需额外依赖只需导入 Flutter 核心包dartimport package:flutter/material.dart;总结CustomPaint是 Flutter 自定义绘制的核心通过CustomPainter实现绘制逻辑Canvas提供具体绘制方法核心步骤定义CustomPainter实现paint绘制逻辑和shouldRepaint重绘判断再通过CustomPaint组件承载进阶场景可通过接收动态参数实现状态更新或使用foregroundPainter实现多层绘制注意性能优化减少不必要的对象创建和重绘。