Flutter使用TextFormField构建大网格时性能低下问题求助
问题场景
展示由大量TextFormField组成的网格时,切换到「Practise」模式(从Text组件切换为TextFormField)需要等待2秒才能完成渲染,设备性能无明显问题,即使仅返回简单的TextFormField()也存在性能瓶颈。
相关代码
Widget cell({int rowIndex = 0, int columnIndex = 0, bool realIndex = false}) { return GestureDetector( onTap: () { if (practising) return; setState(() { selected['row'] = rowIndex; selected['column'] = columnIndex; }); }, child: Container( padding: EdgeInsets.all(realIndex || !practising ? 8 : 5.5), decoration: BoxDecoration( borderRadius: realIndex ? const BorderRadius.only( topLeft: Radius.circular(10), topRight: Radius.circular(10), bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10), ) : columnIndex == 9 ? const BorderRadius.only( bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10), ) : null, color: selected['column'] == columnIndex ? Helpers.hexToColor(colors[rowIndex]) : null, ), child: Center( child: !realIndex && practising ? SizedBox( height: 25, child: TextFormField( controller: textControllers[rowIndex][columnIndex], keyboardType: TextInputType.number, showCursor: false, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric( horizontal: 0, vertical: 0), fillColor: showColors ? true ? Colors.green : Colors.red : null, filled: showColors, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: 2, color: showColors ? true ? Colors.green[800]! : Colors.red[800]! : Colors.grey, ), ), ), textAlign: TextAlign.center, ), ) : Text( ((rowIndex + 1) * (columnIndex + 1)).toString() + (realIndex ? 'x' : ''), style: TextStyle( fontWeight: realIndex ? FontWeight.bold : null, color: selected['column'] == columnIndex ? Colors.white : null, ), ), ), ), ); }
具体优化方案
1. 改用懒加载组件渲染网格
不要一次性创建所有TextFormField,使用GridView.builder(或ListView.builder)代替直接生成所有子组件。懒加载只会渲染当前可见区域的组件,大幅减少初始渲染的组件数量,提升切换速度。
示例:
GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 10, // 你的列数 ), itemCount: totalCells, // 总单元格数 itemBuilder: (context, index) { int rowIndex = index ~/ 10; int columnIndex = index % 10; return cell(rowIndex: rowIndex, columnIndex: columnIndex); }, )
2. 缓存InputDecoration实例
每次build时创建新的InputDecoration会产生额外的对象开销,把通用的装饰实例缓存为静态常量,减少重复创建:
// 在组件类中定义静态常量 static const InputDecoration _textFieldDecoration = InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 0), border: OutlineInputBorder(), ); // 在TextFormField中使用 decoration: _textFieldDecoration.copyWith( fillColor: showColors ? (true ? Colors.green : Colors.red) : null, filled: showColors, enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: 2, color: showColors ? (true ? Colors.green[800]! : Colors.red[800]!) : Colors.grey, ), ), ),
3. 拆分独立组件,减少重建范围
把cell函数拆分为独立的StatefulWidget(比如GridCell),并使用AutomaticKeepAliveClientMixin保持组件状态,避免切换或滚动时不必要的重建。同时,将practising、showColors等状态通过ValueListenableBuilder监听,只在状态变化时更新需要的部分,而不是全量重建整个网格。
4. 禁用TextFormField不必要的特性
关闭自动校正、输入建议等不需要的功能,减少TextFormField的初始化开销:
TextFormField( autocorrect: false, enableSuggestions: false, // ... 其他配置 )
5. 优化State更新方式
不要使用setState更新整个页面状态,改用ValueNotifier、ChangeNotifier等局部状态管理方式,只通知需要更新的组件,避免全量重建。比如把practising、showColors、selected都改成ValueNotifier,通过ValueListenableBuilder监听变化。
内容的提问来源于stack exchange,提问作者Dani

