Flutter.源码分析.flutter/packages/flutter/lib/src/widgets/scroll_view.dart/GridView

Flutter.源码分析 GridView flutter/packages/flutter/lib/src/widgets/scroll_view.dart/GridView


李俊才 的个人博客blog.csdn.net/qq_28550263

本文地址blog.csdn.net/qq_28550263...

本文提供 Flutter 框架中 GridView 类源码注释的中文翻译以及必要的分析解说。


目 录


1. 类注释部分

dart 复制代码
/// 一个可滚动的二维组件数组。
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=bLOtZDTm4H8}
///
/// 网格的主轴方向是其滚动的方向([scrollDirection])。
///
/// 最常用的网格布局是 [GridView.count],它创建一个在交叉轴上有固定数量的瓷砖的布局,和
/// [GridView.extent],它创建一个瓷砖具有最大交叉轴范围的布局。自定义的 [SliverGridDelegate] 可以产生任意的2D
/// 子组件布局,包括不对齐或重叠的布局。
///
/// 要创建一个具有大量(或无限)子组件的网格,使用 [GridView.builder] 构造函数,配合
/// [SliverGridDelegateWithFixedCrossAxisCount] 或 [SliverGridDelegateWithMaxCrossAxisExtent] 
/// 作为 [gridDelegate]。
///
/// 要使用自定义的 [SliverChildDelegate],使用 [GridView.custom]。
///
/// 要创建一个线性的子组件数组,使用 [ListView]。
///
/// 要控制滚动视图的初始滚动偏移,提供一个设置了 [ScrollController.initialScrollOffset] 属性的 [controller]。
///
/// ## 转换到 [CustomScrollView]
///
/// [GridView] 基本上是一个在其 [CustomScrollView.slivers] 属性中有一个 [SliverGrid] 的 [CustomScrollView]。
///
/// 如果 [GridView] 不再足够,例如因为滚动视图要同时有一个网格和一个列表,或者因为网格要与 [SliverAppBar] 结合等,
/// 那么从使用 [GridView] 到直接使用 [CustomScrollView] 的代码移植是直接的。
///
/// [GridView] 上的 [key],[scrollDirection],[reverse],[controller],[primary],[physics],
/// 和 [shrinkWrap] 属性直接映射到 [CustomScrollView] 上同名的属性。
///
/// [CustomScrollView.slivers] 属性应该是一个只包含 [SliverGrid] 的列表。
///
/// [GridView] 上的 [childrenDelegate] 属性对应于 [SliverGrid.delegate] 属性,
/// 而 [GridView] 上的 [gridDelegate] 属性对应于 [SliverGrid.gridDelegate] 属性。
///
/// [GridView],[GridView.count] 和 [GridView.extent]
/// 构造函数的 `children` 参数对应于 [childrenDelegate] 是一个具有相同参数的 [SliverChildListDelegate]。
/// [GridView.builder] 构造函数的 `itemBuilder` 和 `childCount` 参数对应于 [childrenDelegate] 是一个具有匹配参数的 [SliverChildBuilderDelegate]。
///
/// [GridView.count] 和 [GridView.extent] 构造函数创建
/// 自定义网格委托,并在 [SliverGrid] 上有同名的构造函数以便于转换:分别是 [SliverGrid.count] 和
/// [SliverGrid.extent]。
///
/// [padding] 属性对应于在 [CustomScrollView.slivers] 属性中有一个 [SliverPadding] 而不是网格本身,
/// 并且 [SliverGrid] 是 [SliverPadding] 的子组件。
///
/// 一旦代码被移植为使用 [CustomScrollView],其他的 slivers,如 [SliverList] 或 [SliverAppBar],
/// 可以放在 [CustomScrollView.slivers] 列表中。
///
/// {@tool snippet}
/// 这个示例演示了如何创建一个有两列的 [GridView]。子组件之间的间距使用 `crossAxisSpacing` 和 `mainAxisSpacing` 属性设置。
///
/// ![GridView 显示了两列的六个具有不同背景颜色的子组件](https://flutter.github.io/assets-for-api-docs/assets/widgets/grid_view.png)
/// 
/// ```dart
/// GridView.count(
///   primary: false,
///   padding: const EdgeInsets.all(20),
///   crossAxisSpacing: 10,
///   mainAxisSpacing: 10,
///   crossAxisCount: 2,
///   children: <Widget>[
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[100],
///       child: const Text("He'd have you all unravel at the"),
///     ),
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[200],
///       child: const Text('Heed not the rabble'),
///     ),
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[300],
///       child: const Text('Sound of screams but the'),
///     ),
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[400],
///       child: const Text('Who scream'),
///     ),
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[500],
///       child: const Text('Revolution is coming...'),
///     ),
///     Container(
///       padding: const EdgeInsets.all(8),
///       color: Colors.teal[600],
///       child: const Text('Revolution, they...'),
///     ),
///   ],
/// )
/// ```
/// {@end-tool}
///
/// {@tool snippet}
/// 这个示例展示了如何使用 [CustomScrollView] 和 [SliverGrid] 创建与上一个示例相同的网格。
///
/// ![CustomScrollView 包含一个 SliverGrid,它显示了两列的六个具有不同背景颜色的子组件](https://flutter.github.io/assets-for-api-docs/assets/widgets/grid_view_custom_scroll.png)
///
/// ```dart
/// CustomScrollView(
///   primary: false,
///   slivers: <Widget>[
///     SliverPadding(
///       padding: const EdgeInsets.all(20),
///       sliver: SliverGrid.count(
///         crossAxisSpacing: 10,
///         mainAxisSpacing: 10,
///         crossAxisCount: 2,
///         children: <Widget>[
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[100],
///             child: const Text("He'd have you all unravel at the"),
///           ),
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[200],
///             child: const Text('Heed not the rabble'),
///           ),
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[300],
///             child: const Text('Sound of screams but the'),
///           ),
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[400],
///             child: const Text('Who scream'),
///           ),
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[500],
///             child: const Text('Revolution is coming...'),
///           ),
///           Container(
///             padding: const EdgeInsets.all(8),
///             color: Colors.green[600],
///             child: const Text('Revolution, they...'),
///           ),
///         ],
///       ),
///     ),
///   ],
/// )
/// ```
/// {@end-tool}
///
/// 默认情况下,[GridView] 会自动填充网格的滚动边界的限制,以避免 [MediaQuery] 的填充指示的部分遮挡。
/// 要避免这种行为,用零 [padding] 属性覆盖。
///
/// {@tool snippet}
/// 下面的示例演示了如何使用 [MediaQuery.removePadding] 覆盖默认的顶部填充。
///
/// ```dart
/// Widget myWidget(BuildContext context) {
///   return MediaQuery.removePadding(
///     context: context,
///     removeTop: true,
///     child: GridView.builder(
///       gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
///         crossAxisCount: 3,
///       ),
///       itemCount: 300,
///       itemBuilder: (BuildContext context, int index) {
///         return Card(
///           color: Colors.amber,
///           child: Center(child: Text('$index')),
///         );
///       }
///     ),
///   );
/// }
/// ```
/// {@end-tool}
///
/// {@tool dartpad}
/// 这个示例展示了在 [GridView] 或 [ListView] 中 [ListTile] 选择的自定义实现。
/// 长按任何 ListTile 以启用选择模式。
///
/// ** 查看 examples/api/lib/widgets/scroll_view/list_view.0.dart 中的代码 **
/// {@end-tool}
///
/// 另请参阅:
///
///  * [SingleChildScrollView],这是一个有一个单一子组件的可滚动组件。
///  * [ListView],这是一个可滚动的,线性的组件列表。
///  * [PageView],这是一个滚动的子组件列表,每个子组件都是视口的大小。
///  * [CustomScrollView],这是一个创建自定义滚动效果的可滚动组件。
///  * [SliverGridDelegateWithFixedCrossAxisCount],它创建一个在交叉轴上有固定数量的瓷砖的布局。
///  * [SliverGridDelegateWithMaxCrossAxisExtent],它创建一个瓷砖具有最大交叉轴范围的布局。
///  * [ScrollNotification] 和 [NotificationListener],它们可以用来观察滚动位置,而无需使用 [ScrollController]。
///  * [布局组件目录](https://flutter.dev/widgets/layout/)。
class GridView extends BoxScrollView {
  // ...
}

2. 默认构造函数部分

dart 复制代码
  /// 使用自定义 [SliverGridDelegate] 创建一个可滚动的二维组件数组。
  ///
  /// [gridDelegate] 参数不能为空。
  ///
  /// `addAutomaticKeepAlives` 参数对应于 [SliverChildListDelegate.addAutomaticKeepAlives] 属性。
  /// `addRepaintBoundaries` 参数对应于 [SliverChildListDelegate.addRepaintBoundaries] 属性。两者都不能为 null。
  GridView({
    super.key,
    super.scrollDirection,
    super.reverse,
    super.controller,
    super.primary,
    super.physics,
    super.shrinkWrap,
    super.padding,
    required this.gridDelegate,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    super.cacheExtent,
    List<Widget> children = const <Widget>[],
    int? semanticChildCount,
    super.dragStartBehavior,
    super.clipBehavior,
    super.keyboardDismissBehavior,
    super.restorationId,
  }) : childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         semanticChildCount: semanticChildCount ?? children.length,
       );

从 GridView 默认构造函数的结构可以看出,它本质上不过是创建了一个 SliverChildListDelegate 对象并赋值给 childrenDelegate

SliverChildListDelegateSliverChildDelegate 的一个实现,它使用一个固定的子部件列表来生成网格的子部件。这里,children 参数就是这个列表。另外,addAutomaticKeepAlivesaddRepaintBoundariesaddSemanticIndexes 参数用于控制子部件的生命周期、是否添加重绘边界和语义索引。

另外一方面,该构造函数种调用了其父类(BoxScrollView )的构造函数。semanticChildCount 参数用于语义分析,它表示 GridView 中的子部件数量。如果 semanticChildCountnull,则使用 children.length 作为默认值。

3. GridView.builder构造函数部分

GridView.builder 构造函数用于创建一个可以滚动的,按需创建的二维部件数组。这对于具有大量(或无限)子部件的网格视图非常合适,因为构建器只会为实际可见的子部件调用。

dart 复制代码
  /// 创建一个可滚动的,按需创建的二维部件数组。
  ///
  /// 对于具有大量(或无限)子部件的网格视图,此构造函数是合适的,因为构建器只会为实际可见的子部件调用。
  ///
  /// 提供非空的 `itemCount` 可以提高 [GridView] 估计最大滚动范围的能力。
  ///
  /// `itemBuilder` 只会被调用大于等于零且小于 `itemCount` 的索引。
  ///
  /// {@macro flutter.widgets.ListView.builder.itemBuilder}
  ///
  /// {@macro flutter.widgets.PageView.findChildIndexCallback}
  ///
  /// [gridDelegate] 参数是必需的。
  ///
  /// `addAutomaticKeepAlives` 参数对应于 [SliverChildBuilderDelegate.addAutomaticKeepAlives] 属性。
  /// `addRepaintBoundaries` 参数对应于 [SliverChildBuilderDelegate.addRepaintBoundaries] 属性。
  /// `addSemanticIndexes` 参数对应于 [SliverChildBuilderDelegate.addSemanticIndexes] 属性。
  GridView.builder({
    super.key,
    super.scrollDirection,
    super.reverse,
    super.controller,
    super.primary,
    super.physics,
    super.shrinkWrap,
    super.padding,
    required this.gridDelegate,
    required NullableIndexedWidgetBuilder itemBuilder,
    ChildIndexGetter? findChildIndexCallback,
    int? itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    super.cacheExtent,
    int? semanticChildCount,
    super.dragStartBehavior,
    super.keyboardDismissBehavior,
    super.restorationId,
    super.clipBehavior,
  }) : childrenDelegate = SliverChildBuilderDelegate(
         itemBuilder,
         findChildIndexCallback: findChildIndexCallback,
         childCount: itemCount,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         semanticChildCount: semanticChildCount ?? itemCount,
       );

从代码可以看到,这个构造函数接收多个参数,其中最重要的两个参数是 gridDelegateitemBuilder

  • gridDelegate 是一个 SliverGridDelegate 对象,它决定了网格的布局。这是一个必需的参数。
  • itemBuilder 是一个函数,它接收一个 BuildContext 和一个索引,然后返回一个 Widget。这个函数只会被调用大于等于零且小于 itemCount 的索引。这是一个必需的参数。

GridView.builder 构造函数的工作原理是,当需要渲染一个子部件时,它会调用 itemBuilder 函数,传入当前的 BuildContext 和子部件的索引,然后将返回的 组件 添加到网格中。这样,只有当子部件实际需要显示时,才会调用 itemBuilder 函数创建子部件。

此外,GridView.builder 还接收一些其他参数,如 itemCountaddAutomaticKeepAlivesaddRepaintBoundariesaddSemanticIndexes,这些参数用于控制 GridView 的行为。

最后,GridView.builder 通过 SliverChildBuilderDelegate 创建了一个 childrenDelegate,然后传递给 GridView 的父类构造函数。这个 childrenDelegate 决定了如何为 GridView 创建子部件。

4. GridView.custom 构造函数部分

kotlin 复制代码
  /// 使用自定义 [SliverGridDelegate] 和自定义 [SliverChildDelegate] 创建一个可滚动的二维部件数组。
  ///
  /// 要使用 [IndexedWidgetBuilder] 回调来构建子部件,可以使用 [SliverChildBuilderDelegate] 或使用 [GridView.builder] 构造函数。
  ///
  /// [gridDelegate] 和 [childrenDelegate] 参数不能为空。
  const GridView.custom({
    super.key,
    super.scrollDirection,
    super.reverse,
    super.controller,
    super.primary,
    super.physics,
    super.shrinkWrap,
    super.padding,
    required this.gridDelegate,
    required this.childrenDelegate,
    super.cacheExtent,
    super.semanticChildCount,
    super.dragStartBehavior,
    super.keyboardDismissBehavior,
    super.restorationId,
    super.clipBehavior,
  });

GridView.custom 构造函数用于创建一个可滚动的二维部件数组,它允许你完全自定义 **SliverGridDelegate **和 SliverChildDelegate

  • SliverGridDelegate 决定了网格的布局,例如每行的列数、每个子部件的尺寸等。
  • SliverChildDelegate 决定了如何生成网格的子部件。你可以使用 SliverChildBuilderDelegate 来按需生成子部件,或者使用 SliverChildListDelegate 来生成一个固定列表的子部件。

GridView.custom 构造函数接收多个参数,其中最重要的两个参数是 gridDelegate 和 childrenDelegate,这两个参数都是必需的。

  • gridDelegate 是一个 SliverGridDelegate 对象,它决定了网格的布局。
  • childrenDelegate 是一个 SliverChildDelegate 对象,它决定了如何为 GridView 创建子部件。

GridView.custom 会根据 gridDelegate 的设置来布局网格,然后调用 childrenDelegate 来生成子部件。这样,你可以完全自定义 GridView 的布局和子部件的生成方式。

在这个构造函数的实现种:

  • gridDelegate 实现网格的布局工作:gridDelegateSliverGridDelegate 类型的对象,它是一个委托,负责定义网格的布局。具体来说,它决定了网格中每行的列数,以及每个格子的大小。当 GridView 需要布局其子部件时,它会调用 gridDelegate 的方法来获取布局信息。所以,你可以说 gridDelegate 委托了网格的布局工作。
  • childrenDelegate 实现子部件的创建工作:childrenDelegateSliverChildDelegate 类型的对象,它是一个委托,负责创建网格的子部件。具体来说,当 GridView 需要渲染一个新的子部件时,它会调用 childrenDelegate 的方法来创建这个子部件。

5. GridView.count 构造函数部分

GridView.count 构造函数用于创建一个可滚动的二维部件数组,其中交叉轴上有固定数量的格子。这个构造函数接收多个参数,其中最重要的是 crossAxisCount,它决定了交叉轴上的格子数量。此外,还可以设置 mainAxisSpacing 和 crossAxisSpacing 来控制格子之间的间距,以及 childAspectRatio 来控制每个格子的宽高比。

该构造函数的代码为:

php 复制代码
  /// 创建一个可滚动的,二维部件数组,交叉轴上有固定数量的格子。
  ///
  /// 使用 [SliverGridDelegateWithFixedCrossAxisCount] 作为 [gridDelegate]。
  ///
  /// `addAutomaticKeepAlives` 参数对应于 [SliverChildListDelegate.addAutomaticKeepAlives] 属性。
  /// `addRepaintBoundaries` 参数对应于 [SliverChildListDelegate.addRepaintBoundaries] 属性。两者都不能为空。
  ///
  /// 另请参阅:
  ///
  ///  * [SliverGrid.count],[SliverGrid] 的等效构造函数。
  GridView.count({
    super.key,
    super.scrollDirection,
    super.reverse,
    super.controller,
    super.primary,
    super.physics,
    super.shrinkWrap,
    super.padding,
    required int crossAxisCount,
    double mainAxisSpacing = 0.0,
    double crossAxisSpacing = 0.0,
    double childAspectRatio = 1.0,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    super.cacheExtent,
    List<Widget> children = const <Widget>[],
    int? semanticChildCount,
    super.dragStartBehavior,
    super.keyboardDismissBehavior,
    super.restorationId,
    super.clipBehavior,
  }) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisCount: crossAxisCount,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),
       childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         semanticChildCount: semanticChildCount ?? children.length,
       );

从代码可以看出,GridView.count 构造函数会根据 crossAxisCountmainAxisSpacingcrossAxisSpacingchildAspectRatio 的值来布局网格,然后根据 children 列表来创建子部件。这使得你可以轻松地创建一个具有固定列数的网格视图。

GridView.count 构造函数中,gridDelegate 被设置为 SliverGridDelegateWithFixedCrossAxisCount 对象。这个对象会根据 crossAxisCountmainAxisSpacingcrossAxisSpacingchildAspectRatio 的值来布局网格。

childrenDelegate 被设置为 SliverChildListDelegate 对象,它会根据传入的 children 列表来创建子部件。addAutomaticKeepAlivesaddRepaintBoundariesaddSemanticIndexes 参数会传递给 SliverChildListDelegate,用于控制子部件的生命周期、是否添加重绘边界和语义索引。

6. GridView.extent构造函数部分

GridView.extent 构造函数用于创建一个可滚动的二维部件数组,其中交叉轴上的每个格子都有最大的宽度。

这个构造函数接收多个参数,其中最重要的是 maxCrossAxisExtent,它决定了交叉轴上每个格子的最大宽度。此外,还可以设置 mainAxisSpacing 和 crossAxisSpacing 来控制格子之间的间距,以及 childAspectRatio 来控制每个格子的宽高比。

该构造函数源码为:

php 复制代码
  /// 创建一个可滚动的,二维部件数组,每个格子在交叉轴上都有最大的范围。
  ///
  /// 使用 [SliverGridDelegateWithMaxCrossAxisExtent] 作为 [gridDelegate]。
  ///
  /// `addAutomaticKeepAlives` 参数对应于 [SliverChildListDelegate.addAutomaticKeepAlives] 属性。
  /// `addRepaintBoundaries` 参数对应于 [SliverChildListDelegate.addRepaintBoundaries] 属性。两者都不能为空。
  ///
  /// 另请参阅:
  ///
  ///  * [SliverGrid.extent],[SliverGrid] 的等效构造函数。
  GridView.extent({
    super.key,
    super.scrollDirection,
    super.reverse,
    super.controller,
    super.primary,
    super.physics,
    super.shrinkWrap,
    super.padding,
    required double maxCrossAxisExtent,
    double mainAxisSpacing = 0.0,
    double crossAxisSpacing = 0.0,
    double childAspectRatio = 1.0,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    super.cacheExtent,
    List<Widget> children = const <Widget>[],
    int? semanticChildCount,
    super.dragStartBehavior,
    super.keyboardDismissBehavior,
    super.restorationId,
    super.clipBehavior,
  }) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
         maxCrossAxisExtent: maxCrossAxisExtent,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),
       childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         semanticChildCount: semanticChildCount ?? children.length,
       );

GridView.extent 构造函数会根据 maxCrossAxisExtentmainAxisSpacingcrossAxisSpacingchildAspectRatio 的值来布局网格,然后根据 children 列表来创建子部件。这使得你可以轻松地创建一个具有固定最大宽度的网格视图。

GridView.extent 构造函数中,gridDelegate 被设置为 SliverGridDelegateWithMaxCrossAxisExtent 对象。这个对象会根据 maxCrossAxisExtentmainAxisSpacingcrossAxisSpacingchildAspectRatio 的值来布局网格。

childrenDelegate 被设置为 SliverChildListDelegate 对象,它会根据传入的 children 列表来创建子部件。addAutomaticKeepAlivesaddRepaintBoundariesaddSemanticIndexes 参数会传递给 SliverChildListDelegate,用于控制子部件的生命周期、是否添加重绘边界和语义索引。

7. gridDelegate属性

gridDelegate 是 GridView 类中的一个属性,它的类型是 SliverGridDelegate。这个属性是一个委托(delegate),它决定了 GridView 中子部件的布局。

其源代码为:

dart 复制代码
  /// 一个委托,控制 [GridView] 中子部件的布局。
  ///
  /// [GridView],[GridView.builder] 和 [GridView.custom] 构造函数允许你明确指定这个委托。其他构造函数隐式创建一个 [gridDelegate]。
  final SliverGridDelegate gridDelegate;

gridDelegate 属性的作用就是定义 GridView 中子部件的布局。这使得 GridView 可以灵活地适应各种需求,例如创建固定列数的网格,或者创建具有固定最大宽度的网格。

SliverGridDelegate 是一个抽象类,它有两个常用的子类:SliverGridDelegateWithFixedCrossAxisCountSliverGridDelegateWithMaxCrossAxisExtent

  • SliverGridDelegateWithFixedCrossAxisCount 创建一个网格,其中交叉轴上有固定数量的格子。你可以指定交叉轴上的格子数量,以及格子之间的间距和宽高比。
  • SliverGridDelegateWithMaxCrossAxisExtent 创建一个网格,其中交叉轴上的每个格子都有最大的宽度。你可以指定每个格子的最大宽度,以及格子之间的间距和宽高比。

GridViewGridView.builderGridView.custom 构造函数中,你可以明确指定 gridDelegate。在其他构造函数中,gridDelegate 会自动创建。

8. childrenDelegate属性

arduino 复制代码
  /// 一个委托,为 [GridView] 提供子部件。
  ///
  /// [GridView.custom] 构造函数允许你明确指定这个委托。其他构造函数创建一个包装给定子部件列表的 [childrenDelegate]。
  final SliverChildDelegate childrenDelegate;

可以看到,childrenDelegate 属性类型为 SliverChildDelegate 。这个属性是一个 委托(delegate),它决定了如何为 GridView 创建子部件。

SliverChildDelegate 是一个抽象类,它有两个常用的子类:SliverChildListDelegateSliverChildBuilderDelegate。其中:

  • SliverChildListDelegate 接收一个固定长度的子部件列表,然后按照列表顺序创建子部件。
  • SliverChildBuilderDelegate 接收一个构建函数,然后按需创建子部件。这对于具有大量子部件的 GridView 非常有用,因为只有当子部件实际需要显示时,才会调用构建函数创建子部件。

GridView.custom 构造函数中,你可以明确指定 childrenDelegate。在其他构造函数中,childrenDelegate 会自动创建,通常是包装给定的子部件列表。

因此,childrenDelegate 属性的作用就是定义如何为 GridView 创建子部件。这使得 GridView 可以灵活地适应各种需求,例如创建固定数量的子部件,或者按需创建子部件。

9. buildChildLayout方法

buildChildLayout 负责构建 GridView 的子布局。

dart 复制代码
  @override
  Widget buildChildLayout(BuildContext context) {
    return SliverGrid(
      delegate: childrenDelegate,
      gridDelegate: gridDelegate,
    );
  }

buildChildLayout 方法的作用就是根据 GridView 的属性来创建一个 SliverGrid 对象,这个 SliverGrid 对象定义了 GridView 的子布局。

这个方法接收一个 BuildContext 对象作为参数,然后返回一个 SliverGrid 对象。

SliverGrid 是一个可以在网格中显示其子项的滑动列表。它需要两个参数:delegategridDelegate

  1. delegate 参数是一个 SliverChildDelegate 对象,它决定了如何创建和布局子项。在 GridView 中,这个参数的值是 childrenDelegate 属性。
  2. gridDelegate 参数是一个 SliverGridDelegate 对象,它决定了网格的布局。在 GridView 中,这个参数的值是 gridDelegate 属性。
相关推荐
Ranye1233 小时前
从 JS 到 Dart:语法基础
javascript·flutter·dart
我要最优解10 小时前
关于在mac中配置Java系统环境变量
java·flutter·macos
江上清风山间明月2 天前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能2 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人2 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen2 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang3 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang3 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1233 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-3 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode