关于flutter:flutter系列之flutter中常用的GridView-layout详解

42次阅读

共计 4196 个字符,预计需要花费 11 分钟才能阅读完成。

简介

GridView 是一个网格化的布局,如果在填充的过程中子组件超出了展现的范畴的时候,那么 GridView 会主动滚动。

因为这个滚动的个性,所以 GridView 是一个十分好用的 Widget。明天咱们一起来摸索一下 GridView 这个 layout 组件的机密。

GridView 详解

GridView 是一个可滚动的 view, 也就是 ScrollView, 事实上 GridView 继承自 BoxScrollView:

class GridView extends BoxScrollView

而它的父类 BoxScrollView,则是继承自 ScrollView:

abstract class BoxScrollView extends ScrollView 

能够看到 BoxScrollView 是一个抽象类,它有两个子类,别离是明天咱们要讲的 GridView 和下期要讲的 ListView。

这两个组件的区别是 GridView 是一个 2D 的布局,而 ListView 是一个线性 layout 的布局。

作为 BoxScrollView 的子类,GridView 须要实现 buildChildLayout 办法如下所示:

  @override
  Widget buildChildLayout(BuildContext context) {
    return SliverGrid(
      delegate: childrenDelegate,
      gridDelegate: gridDelegate,
    );
  }

这里 GridView 返回了一个 SliverGrid,这个 SliverGrid 中有两个属性,别离是 childrenDelegate 和 gridDelegate。

其中 gridDelegate 是一个 SliverGridDelegate 的实例,用来管制子组件在 GridView 中的布局。

childrenDelegate 是一个 SliverChildDelegate 的实例,用来生成 GridView 中的子组件。

这两个属性在 GridView 的构造函数中有应用,咱们接下来会具体进行解说。

GridView 的构造函数

GridView 有很多个构造函数, 首先是蕴含所有参数的全参数构造函数:

  GridView({
    Key? key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController? controller,
    bool? primary,
    ScrollPhysics? physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry? padding,
    required this.gridDelegate,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double? cacheExtent,
    List<Widget> children = const <Widget>[],
    int? semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
    Clip clipBehavior = Clip.hardEdge,
    ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    String? restorationId,
  })

在这个构造函数中,须要传入自定义的 gridDelegate,所以在构造函数中 gridDelegate 是 required 状态:

required this.gridDelegate

下面提到了 GridView 中的两个自定义属性,还有一个是 childrenDelegate, 这个属性是依据传入的其余参数结构而成的,如下所示:

childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),

另外一个 GridView 的构造函数叫做 GridView.builder,这个构造函数和默认的构造函数的区别在于 childrenDelegate 的实现不同,咱们来看下 GridView.builder 中 childrenDelegate 的实现:

childrenDelegate = SliverChildBuilderDelegate(
         itemBuilder,
         childCount: itemCount,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),

比照发现,GridView.builder 中的 childrenDelegate 多了两个参数,别离是 itemBuilder 和 itemCount。

那么这个两个参数是做什么用的呢?

考虑一下一个有很多 chil 的 GridView,为了晋升 GridView 的展现性能,咱们不可能一下取出所有的 child 元素进行构建,而是会在滚动中进行动态创建和绘制,而这里的 itemCount 就是 child 的最大容量。

而 itemBuilder 就是一个动态创建 child 的创立器,从而满足了动态创建 child 的需要。

接下来的构造函数叫做 GridView.custom,因为叫做 custom,所以这个构造函数的 SliverGridDelegate 和 SliverChildDelegate 都是能够自定义的,也就是说这两个参数都能够从内部传入, 所以这两个参数都是必须的:

  required this.gridDelegate,
    required this.childrenDelegate

GirdView 还有一个构造函数叫做 GridView.count,这里的 count 是指 GridView 能够指定 cross axis 中能够蕴含的组件个数,所以这里的 gridDelegate 应用的是一个 SliverGridDelegateWithFixedCrossAxisCount:

gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisCount: crossAxisCount,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),

能够设置 crossAxisCount 的值。

最初一个 GridView 的构造函数叫做 GridView.extent,它和 count 的构造函数很相似,不过 extent 提供的是一个 maximum cross-axis extent, 而不是一个固定的 count 值, 所以这里的 gridDelegate 是一个 SliverGridDelegateWithMaxCrossAxisExtent 对象:

gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
         maxCrossAxisExtent: maxCrossAxisExtent,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),

怎么了解呢?举个例子,如果 GirdView 是竖向滚动的,并且它的 width 是 400 pixels, 如果这个时候 maxCrossAxisExtent 被设置为 120,那么一行只能有三列。咱们能够通过调整 maxCrossAxisExtent 的值,来调整 view 的展现状况。

咱们能够依据须要来抉择对应的构造函数,从而满足咱们不同的需要。

GridView 的应用

有了 GridView 的构造函数,GridView 应用起来就很简略了。

比方咱们动态创建一个蕴含 image 的 child,组成一个 gridView:

class GridViewApp extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    return GridView.extent(
        maxCrossAxisExtent: 100,
        padding: const EdgeInsets.all(4),
        mainAxisSpacing: 4,
        crossAxisSpacing: 4,
        children: buildChild(10));
  }

这里的 buildChild 用来生成一个蕴含 Widget 的 list,如下所示:

  List<Widget> buildChild(int number) {
    return List.generate(number, (i) => Container(child: Image.asset('images/head.jpg')));
  }

最初将结构的 GridViewApp 放到 Scaffold 的 body 中运行:

  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(title: Text(widget.title),
      ),
      body: Center(child: GridViewApp(),
      ),
    );
  }

最初咱们能够失去上面的图像:

这里咱们应用的是 GridView.extent 构造函数,大家能够自行尝试其余的构造函数。

总结

GridView 是一个咱们在日常工作中常常会应用的组件,心愿大家可能熟练掌握。

本文的例子:https://github.com/ddean2009/learn-flutter.git

正文完
 0