Flutter自定义可滚动动态高度有机网格视图问题求助
解决CustomMultiChildLayout实现的网格无法滚动的问题
要解决这个问题,核心是让CustomMultiChildLayout拥有明确的尺寸,这样滚动组件才能正确计算可滚动区域。具体修改如下:
在
CustomGridDelegate中计算总高度并设置布局尺寸CustomMultiChildLayout的尺寸由MultiChildLayoutDelegate的performLayout方法决定,必须调用setSize明确布局的总大小。我们根据子组件数量计算网格总高度,再设置给布局。将网格组件包裹在
SingleChildScrollView中
有了明确的布局高度后,用SingleChildScrollView包裹网格组件,即可实现滚动功能。修正子组件高度计算
原代码中childHeight硬编码为60,但实际子组件(ContainerWidget)包含上下各8的padding,加上容器本身50的高度,总高度应为66,修正此数值可避免布局重叠。
修改后的完整代码:
class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Column( children: [ Expanded( child: OrganicGrid(count: 50), ), ], ), ); } } class OrganicGrid extends StatelessWidget { final int count; const OrganicGrid({ required this.count, super.key, }); @override Widget build(BuildContext context) { return SingleChildScrollView( child: CustomGrid( children: List.generate(count, (index) => ContainerWidget(id: index + 1)), ), ); } } class ContainerWidget extends StatelessWidget { final int id; const ContainerWidget({ required this.id, super.key, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Container( height: 50, decoration: const BoxDecoration( color: Colors.green, ), child: Center( child: Text( "Text $id", style: TextStyle(color: Colors.white), )), ), ); } } class CustomGrid extends StatelessWidget { final List<Widget> children; const CustomGrid({required this.children, super.key}); @override Widget build(BuildContext context) { List<Widget> rows = []; bool oddExist = children.length % 2 != 0; if (oddExist) { rows.add(LayoutId(id: 0, child: children[0])); } if (oddExist) { for (int i = 1; i < children.length; i++) { rows.add(LayoutId(id: i, child: children[i])); } } else { for (int i = 1; i <= children.length; i++) { rows.add(LayoutId(id: i, child: children[i - 1])); } } return CustomMultiChildLayout( key: key, delegate: CustomGridDelegate(numRows: rows.length, oddExist: oddExist), children: rows, ); } } class CustomGridDelegate extends MultiChildLayoutDelegate { final int numRows; final bool oddExist; CustomGridDelegate({required this.numRows, required this.oddExist}); @override void performLayout(Size size) { const double padding = 8; double width = size.width - padding * 3; double childHeight = 66; // 50容器高度 + 上下各8的padding double dy = 0; double dx = padding; void childLayout(int i) { positionChild(i, Offset(dx, dy)); layoutChild( i, BoxConstraints(minWidth: width / 2, maxWidth: width / 2), ); if (i % 2 == 0) { dy += childHeight; dx = padding; } else { dx = width / 2; dx += padding * 2; } } void zerothChildLayout(int i) { positionChild(i, Offset(dx, dy)); layoutChild( 0, BoxConstraints(minWidth: width + padding), ); dy += childHeight; } if (oddExist) { zerothChildLayout(0); for (int i = 1; i < numRows; i++) { childLayout(i); } } else { for (int i = 1; i <= numRows; i++) { childLayout(i); } } // 计算并设置整个布局的总尺寸 double totalHeight; if (oddExist) { // 首行1个,剩余(numRows-1)个每2个一行 int totalRows = 1 + (numRows - 1) ~/ 2; totalHeight = totalRows * childHeight; } else { // 每2个一行 int totalRows = numRows ~/ 2; totalHeight = totalRows * childHeight; } setSize(Size(size.width, totalHeight)); } @override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false; }
内容的提问来源于stack exchange,提问作者Cloud
相关产品推荐
相关产品推荐

