Flutter带固定表头滚动表格消除ParentDataWidget异常
解决Flutter固定表头滚动表格的"Incorrect use of ParentDataWidget"异常
问题原因分析
出现该异常的核心是ParentDataWidget(此处为Flexible)被放置在了错误的父组件中,具体问题点:
SingleChildScrollView的直接子节点是Flexible,但Flexible仅能作为Row/Column等Flex组件的子节点使用,不能直接嵌套在SingleChildScrollView下。- 内层重复嵌套
Scaffold,外层已存在Scaffold,重复嵌套会导致布局上下文冲突。 SizedBox设置height: screenHeight,结合外层Expanded会触发布局溢出,引发额外错误。- 手动创建24个数据变量,代码冗余且易出错。
修复后的优化代码
// ignore_for_file: camel_case_types, prefer_interpolation_to_compose_strings import 'package:bps_cilacap/restAPI/repository_penduduk_kecamatan.dart'; import 'package:flutter/material.dart'; import 'package:bps_cilacap/format_angka.dart'; class JumlahPendudukKecamatanA extends StatefulWidget { const JumlahPendudukKecamatanA({Key? key}) : super(key: key); @override State<JumlahPendudukKecamatanA> createState() => _JumlahPendudukKecamatanAState(); } RepositoryJumlahPendudukKecamatan jumlahPendudukKecamatan = RepositoryJumlahPendudukKecamatan(); class _JumlahPendudukKecamatanAState extends State<JumlahPendudukKecamatanA> { @override Widget build(BuildContext context) { final screenHeight = MediaQuery.of(context).size.height - MediaQuery.of(context).padding.top - MediaQuery.of(context).padding.bottom; final screenWidth = MediaQuery.of(context).size.width - MediaQuery.of(context).padding.left - MediaQuery.of(context).padding.right; return Scaffold( body: FutureBuilder( future: jumlahPendudukKecamatan.getData(), builder: (context, snapshot) { if (snapshot.hasData) { List isipendudukkecamatan = snapshot.data as List; // 提取总计行(最后一条数据) final totalData = isipendudukkecamatan.last; // 提取前24条区县数据 final kecamatanDataList = isipendudukkecamatan.take(24).toList(); return Column( children: <Widget>[ // 固定表头行 Container( height: screenHeight * 0.06, child: Row( children: [ Flexible( fit: FlexFit.tight, flex: 4, child: Container( color: Colors.green, alignment: Alignment.center, child: const Text( "Kecamatan", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold), ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Container( color: Colors.green, alignment: Alignment.center, child: const Text( "Lk", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold), ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Container( color: Colors.green, alignment: Alignment.center, child: const Text( "Pr", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold), ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Container( color: Colors.green, alignment: Alignment.center, child: const Text( "Lk + Pr", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold), ), ), ), ], ), ), // 可滚动表格内容 Expanded( child: SingleChildScrollView( child: SizedBox( width: screenWidth, child: Column( children: [ // 循环生成24行区县数据 for (int i = 0; i < kecamatanDataList.length; i++) _buildTableRow( index: i + 1, kecamatan: kecamatanDataList[i].kecamatan, lk: int.parse(kecamatanDataList[i].lk1), pr: int.parse(kecamatanDataList[i].pr1), screenHeight: screenHeight, ), // 总计行 _buildTableRow( index: -1, // 标记为总计行 kecamatan: totalData.kecamatan, lk: int.parse(totalData.lk1), pr: int.parse(totalData.pr1), screenHeight: screenHeight, isTotal: true, ), ], ), ), ), ), ], ); } else if (snapshot.hasError) { return const Center(child: Text('Database Error')); } else { return const Center(child: CircularProgressIndicator(strokeWidth: 3)); } }, ), ); } // 封装表格行组件,复用代码 Widget _buildTableRow({ required int index, required String kecamatan, required int lk, required int pr, required double screenHeight, bool isTotal = false, }) { final textStyle = isTotal ? const TextStyle(fontWeight: FontWeight.bold, fontSize: 16) : const TextStyle(fontWeight: FontWeight.normal); final kecText = isTotal ? kecamatan : "${index.toString().padLeft(2, ' ')}. $kecamatan"; return Container( height: screenHeight * 0.032, padding: const EdgeInsets.symmetric(horizontal: 2), child: Row( children: [ Flexible( fit: FlexFit.tight, flex: 4, child: Align( alignment: Alignment.centerLeft, child: Text( kecText, style: textStyle, ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Align( alignment: Alignment.centerRight, child: Text( Format.convertTo(lk, 0), style: textStyle, ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Align( alignment: Alignment.centerRight, child: Text( Format.convertTo(pr, 0), style: textStyle, ), ), ), Flexible( fit: FlexFit.tight, flex: 2, child: Align( alignment: Alignment.centerRight, child: Text( Format.convertTo(lk + pr, 0), style: textStyle, ), ), ), ], ), ); } }
关键优化点说明
- 移除错误嵌套的Flexible:删除
SingleChildScrollView下的Flexible,SingleChildScrollView无需弹性布局子节点。 - 删除冗余Scaffold:外层已存在
Scaffold,内层重复嵌套会导致布局上下文冲突,直接移除。 - 循环生成表格行:用
for循环+封装的_buildTableRow组件替代手动创建24个变量,减少代码冗余,提升可维护性。 - 修复总数计算错误:将原代码中错误的
lk1 + pr2修正为lk + pr,保证数据准确性。 - 优化布局结构:表头行固定高度,表格内容通过
Expanded填充剩余空间,SingleChildScrollView仅负责垂直滚动,避免布局溢出。 - 移除无用PageView:原代码中
PageView.builder的itemCount=1无实际意义,直接返回布局内容即可。
内容的提问来源于stack exchange,提问作者Ahmad Rifai
相关产品推荐
相关产品推荐

