如何避免Scaffold::appBar状态变更时触发CustomPainter::paint()调用
解决AppBar状态变化时CustomPainter不必要重绘的问题
问题根源
当AppBar内按钮状态变化触发父组件PageTestState的build方法重新执行时,_body()会每次新建PageTestPainter实例。即使shouldRepaint返回false,Flutter检测到CustomPainter实例更换后,依然会触发paint()方法调用。
可行解决方案
方案一:缓存CustomPainter实例
在State类中初始化并复用同一个CustomPainter实例,避免每次build都创建新对象:
class PageTestState extends State<PageTest> { late PageTestPaint _painter; @override void initState() { super.initState(); // 初始化一次,后续复用 _painter = PageTestPaint(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, title: const Text('Page Test'), titleTextStyle: const TextStyle(color: Colors.black, fontWeight: FontWeight.bold), centerTitle: true, actions: [ IconButton( icon: const Icon(Icons.radio_button_checked, color: Colors.redAccent), onPressed: () {}, ), ], ), body: _body(), ); } Widget _body() { return Center( child: CustomPaint( painter: _painter, // 使用缓存的实例 ), ); } }
方案二:封装为独立StatelessWidget
将包含CustomPaint的部分抽成单独的无状态组件,父组件重建时,只要子组件无参数变化,就不会重新构建:
// 新增独立组件 class CustomPaintContainer extends StatelessWidget { const CustomPaintContainer({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: CustomPaint( painter: PageTestPaint(), ), ); } } // 修改PageTestState的build方法 class PageTestState extends State<PageTest> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, title: const Text('Page Test'), titleTextStyle: const TextStyle(color: Colors.black, fontWeight: FontWeight.bold), centerTitle: true, actions: [ IconButton( icon: const Icon(Icons.radio_button_checked, color: Colors.redAccent), onPressed: () {}, ), ], ), body: const CustomPaintContainer(), ); } }
原理说明
两种方案的核心都是保证CustomPainter实例不被频繁重建。因为shouldRepaint返回false时,只有当CustomPainter实例本身变化时,Flutter才会触发paint()方法,只要实例稳定,AppBar的状态变化就不会影响到CustomPainter的重绘。
内容的提问来源于stack exchange,提问作者wingchun
相关产品推荐
相关产品推荐

