简介

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