Flutter - 不可滚动的网格
Posted
技术标签:
【中文标题】Flutter - 不可滚动的网格【英文标题】:Flutter - Non-scrollable Grid 【发布时间】:2020-02-03 12:10:09 【问题描述】:有没有办法构建一个本身不可滚动且大小取决于其子级的网格,就像我们可以在行或列中指定 mainAxisSize: MainAxisSize.min 一样?
为您提供全局 -
我正在尝试创建一个取决于设备宽度的响应式布局。 它应该分成两部分,通过列无缝连接。
1) 2 个大小取决于屏幕宽度的大容器,考虑到它们之间的小空间。每个容器的宽度和高度都相同(方形容器)。
2) 相同的想法,但有 3 行,每行包含 3 个较小的容器。 这将创建一个网格。尽管网格本身不能滚动并且其大小将取决于其子级,但这一点非常重要。它只能与 SingleChildScrollView 中包含的页面的其余部分一起滚动。
特别是因为每个容器的高度都需要与其宽度相同,我正在考虑使用行、列和 LayoutBuilder 的组合 - 它们为我提供了我需要的所有功能。
但是,在手动执行操作之前,我想知道是否有一些开箱即用的方法。
【问题讨论】:
【参考方案1】:这样的?
SingleChildScrollView(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(width: 3.0, color: Colors.green),
),
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(width: 3.0, color: Colors.green),
),
),
),
),
),
],
),
Container(
padding: const EdgeInsets.all(10.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: 21,
itemBuilder: (context, index)
return Container(
decoration: BoxDecoration(
border: Border.all(width: 3.0),
),
);
,
),
),
],
),
)
【讨论】:
非常感谢你。我花了将近 10 个小时来做这个......再次感谢伙计。 @Emon 我花了 6 个小时试图解决这个问题,哈哈 "......失去了将近 10 个小时","......花了 6 个小时......" smh,我喜欢编程【参考方案2】:table widget 可能是比 GridView(janstol 的答案)更简单的方法,因为它是专为您正在寻找的东西而构建的。尽管这不适用于您的情况,但如果您的小部件可以具有不同的大小,Table 将特别有用 - 它会相对于每列/行中最宽/最高的小部件(分别)垂直和水平对齐小部件。
这里是 janstol 的解决方案代码重写为使用表。请注意,Table 要求所有行的长度相同,因此您的前两个元素行需要位于表之外。
Widget bigBox = Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(width: 3.0, color: Colors.green),
),
),
),
),
);
Widget smallBox = Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(width: 3.0),
),
),
),
);
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Row(
children: List.filled(2, bigBox),
),
Container(
child: Table(
children: List.filled(
// 7 rows instead of 3 just to demonstrate the scrolling functionality
7,
TableRow(
children: List.filled(3, smallBox),
)
),
),
),
],
),
),
【讨论】:
欢迎提供指向解决方案的链接,但请确保您的答案在没有它的情况下有用:在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在它,然后引用在目标页面不可用的情况下,您链接到的页面的最相关部分。 感谢 Zahra 的反馈,我已经完全重写了我的答案,使其更加彻底,并且无需链接即可独立使用。【参考方案3】:您可以为其创建一个自定义小部件,这是code,用于从google ui 包中创建一个不可滚动的网格小部件。
import 'package:flutter/material.dart';
/// Create a grid.
class GoogleGrid extends StatelessWidget
const GoogleGrid(
Key? key,
this.columnCount = 2,
this.gap,
this.padding,
required this.children,
) : super(key: key);
/// Number of column.
final int columnCount;
/// Gap to separate each cell.
final double? gap;
/// An empty space.
final EdgeInsets? padding;
/// The widgets below this widget in the tree.
final List<Widget> children;
@override
Widget build(BuildContext context)
return Container(
padding: padding,
child: Column(children: _createRows()),
);
List<Widget> _createRows()
final List<Widget> rows = [];
final childrenLength = children.length;
final rowCount = (childrenLength / columnCount).ceil();
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
final List<Widget> columns = _createRowCells(rowIndex);
rows.add(Row(children: columns));
if (rowIndex != rowCount - 1) rows.add(SizedBox(height: gap));
return rows;
List<Widget> _createRowCells(int rowIndex)
final List<Widget> columns = [];
final childrenLength = children.length;
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
final cellIndex = rowIndex * columnCount + columnIndex;
if (cellIndex <= childrenLength - 1)
columns.add(Expanded(child: children[cellIndex]));
else
columns.add(Expanded(child: Container()));
if (columnIndex != columnCount - 1) columns.add(SizedBox(width: gap));
return columns;
使用方法与使用列或行小部件相同,您可以定义列数、间隙、填充和边距。
GoogleGrid(
gap: 16,
padding: const EdgeInsets.all(16),
children: [
Text("1"),
Text("2"),
Text("3"),
Text("4"),
Text("5"),
Text("6"),
],
);
【讨论】:
以上是关于Flutter - 不可滚动的网格的主要内容,如果未能解决你的问题,请参考以下文章