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

简介: GridView是一个网格化的布局,如果在填充的过程中子组件超出了展示的范围的时候,那么GridView会自动滚动。因为这个滚动的特性,所以GridView是一个非常好用的Widget。今天我们一起来探索一下GridView这个layout组件的秘密。

简介

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

相关文章
|
4月前
|
索引
Flutter.源码分析.flutter/packages/flutter/lib/src/widgets/scroll_view.dart/GridView
Flutter.源码分析.flutter/packages/flutter/lib/src/widgets/scroll_view.dart/GridView
33 0
【布局 widget】 Flutter GridView
GridView 独有的参数其实只有一个 gridDelegate,gridDelegate 的作用是为 GridView 布局,制定每行几个 child,空白多少等。
113 0
【布局 widget】 Flutter GridView
|
Web App开发 测试技术 索引
Flutter Web网站之ScrollView+GridView优化
Flutter Web网站之ScrollView+GridView优化
167 0
Flutter Web网站之ScrollView+GridView优化
|
前端开发 Java 开发工具
Flutter(七)——多子元素组件:GridView,CustomScrollView,Flex,Wrap
Flutter(七)——多子元素组件:GridView,CustomScrollView,Flex,Wrap
263 0
Flutter(七)——多子元素组件:GridView,CustomScrollView,Flex,Wrap
Flutter之 GridView
Flutter之 GridView
94 0
Flutter之 GridView
flutter系列之:flutter中常用的Stack layout详解
对于现代APP的应用来说,为了更加美观,通常会需要用到不同图像的堆叠效果,比如在一个APP用户背景头像上面添加一个按钮,表示可以修改用户信息等。 要实现这样的效果,我们需要在一个Image上面堆叠其他的widget对象,flutter为我们提供了这样的一个非常方便的layout组件叫做Stack,今天和大家一起来聊一聊Stack的使用。
flutter系列之:flutter中常用的Stack layout详解
flutter系列之:flutter中常用的ListView layout详解
ListView是包含多个child组件的widget,在ListView中所有的child widget都是以list的形式来呈现的,你可以自定义List的方向,但是和GridView不同的是ListView中的每一个List里面都只包含一个widget。 今天我们来详细了解一下ListView的底层实现和具体的应用。
flutter系列之:flutter中常用的ListView layout详解
flutter系列之:flutter中常用的container layout详解
在上一篇文章中,我们列举了flutter中的所有layout类,并且详细介绍了两个非常常用的layout:Row和Column。 掌握了上面两个基本的layout还是不够的,如果需要应付日常的layout使用,我们还需要掌握多一些layout组件。今天我们会介绍一个功能强大的layout:Container layout。
flutter系列之:flutter中常用的container layout详解
|
存储 前端开发 iOS开发
flutter系列之:UI layout简介
对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。 在flutter中,基本上所有的对象都是widget,对于layout来说也不例外。也就是说在flutter中layout也是用代码来完成的,这和其他的用配置文件来描述layout的语言有所不同。 你可以把layout看做是一种看不见的widget,这些看不见的widget是用来作用在可见的widget对象上,给他们实施一些限制。
flutter系列之:UI layout简介
|
Android开发 容器
Flutter入门:组件Card、SafeArea、PageView、GridView
Card Card对应Material Design中的CardView,使用很简单 Card的两个特点就是阴影和圆角。
493 0