GridView

GridView能够构建一个二维网格列表,其默认结构函数界说如下:

  GridView({
    Key? key,
    Axis scrollDirection = Axis.vertical,//翻滚方向
    bool reverse = false,//组件反向排序
    ScrollController? controller,//翻滚监听
    bool? primary,//内容缺乏不可滑动,值为true,内容缺乏能够尝试滑动。
    ScrollPhysics? physics,//滑动类型设置
    bool shrinkWrap = false,//内容适配
    EdgeInsetsGeometry? padding,//内边距
    required this.gridDelegate,  //署理,设置队伍数量
    bool addAutomaticKeepAlives = true,//缓存相关
    bool addRepaintBoundaries = true,//烘托鸿沟,性能相关
    double? cacheExtent, //设置预烘托区域
    List<Widget> children = const <Widget>[],//子组件
    ...
  })

咱们能够看到,GridViewListView的大多数参数都是相同的,它们的意义也都相同的。咱们唯一需求关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件怎么排列(layout)。

SliverGridDelegate是一个抽象类,界说了GridView Layout相关接口,子类需求经过完成它们来完成具体的布局算法。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCountSliverGridDelegateWithMaxCrossAxisExtent,咱们能够直接运用,下面咱们分别来介绍一下它们。

SliverGridDelegateWithFixedCrossAxisCount

该子类完成了一个横轴为固定数量子元素的layout算法,其结构函数为:

SliverGridDelegateWithFixedCrossAxisCount({
  @required double crossAxisCount, 
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • crossAxisCount:横轴子元素的数量。此属性值确认后子元素在横轴的长度就确认了,即ViewPort横轴长度除以crossAxisCount的商。
  • mainAxisSpacing:主轴方向的间距。
  • crossAxisSpacing:横轴方向子元素的间距。
  • childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后,子元素横轴长度就确认了,然后经过此参数值就能够确认子元素在主轴的长度。

能够发现,子元素的巨细是经过crossAxisCountchildAspectRatio两个参数一起决议的。留意,这里的子元素指的是子组件的最大显现空间,留意保证子组件的实际巨细不要超出子元素的空间。

比如:

GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,//横轴三个子widget
          childAspectRatio: 1.0,//子widget宽高比例
        ),
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast)
      ],
    )

运转作用:

35、Flutter之GridView组件详解

GridView.count

GridView.count结构函数内部运用了SliverGridDelegateWithFixedCrossAxisCount,咱们经过它能够快速的创立横轴固定数量子元素的GridView,上面的示例代码等价于:

GridView.count(
      crossAxisCount: 3,
      childAspectRatio: 1.0,
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    )

SliverGridDelegateWithMaxCrossAxisExtent

该子类完成了一个横轴子元素为固定最大长度的layout算法,其结构函数为:

SliverGridDelegateWithMaxCrossAxisExtent({
  double maxCrossAxisExtent,
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})

maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的,举个比如,假如ViewPort的横轴长度是450,那么当maxCrossAxisExtent的值在区间(450/4,450/3)内的话,子元素终究实际长度都为112.5,而childAspectRatio所指的子元素横轴和主轴的长度比为终究的长度比。其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。

比如:

GridView(
  padding: EdgeInsets.zero,
  gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 120.0,
      childAspectRatio: 2.0 //宽高比为2
  ),
  children: <Widget>[
    Icon(Icons.ac_unit),
    Icon(Icons.airport_shuttle),
    Icon(Icons.all_inclusive),
    Icon(Icons.beach_access),
    Icon(Icons.cake),
    Icon(Icons.free_breakfast),
  ],
);

运转作用:

35、Flutter之GridView组件详解

GridView.extent

GridView.extent结构函数内部运用了SliverGridDelegateWithMaxCrossAxisExtent,咱们经过它能够快速的创立纵轴子元素为固定最大长度的的GridView,上面的示例代码等价于:

GridView.extent(
   maxCrossAxisExtent: 120.0,
   childAspectRatio: 2.0,
   children: <Widget>[
     Icon(Icons.ac_unit),
     Icon(Icons.airport_shuttle),
     Icon(Icons.all_inclusive),
     Icon(Icons.beach_access),
     Icon(Icons.cake),
     Icon(Icons.free_breakfast),
   ],
 );

GridView.builder

上面咱们介绍的GridView都需求一个widget数组作为其子元素,这些方式都会提前将一切子widget都构建好,所以只适用于子widget数量比较少时,当子widget比较多时,咱们能够经过GridView.builder来动态创立子widget。GridView.builder 有必要指定的参数有两个:

GridView.builder(
 ...
 required SliverGridDelegate gridDelegate, 
 required IndexedWidgetBuilder itemBuilder,
)

其中itemBuilder为子widget构建器。

假定咱们需求从一个异步数据源(如网络)分批获取一些Icon,然后用GridView来展示:

import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';
/// @Author wywinstonwy
/// @Date 2022/1/21 8:48 上午
/// @Description: 
class MyGridViewPage extends StatefulWidget {
  const MyGridViewPage({Key? key}) : super(key: key);
  @override
  _MyGridViewPageState createState() => _MyGridViewPageState();
}
class _MyGridViewPageState extends State<MyGridViewPage> {
  List<IconData> _icons = []; //保存Icon数据
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _retrieveIcons();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: getAppBar('GridView'),
      body: _buildGridBuilderView(),
    );
  }
  _buildGridView(){
    return GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,//横轴三个子widget
          childAspectRatio: 1.0,//子widget宽高比例
        ),
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast)
      ],
    );
  }
  _buildGridCountView(){
    return GridView.count(
      crossAxisCount: 3,
      childAspectRatio: 1.0,
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    );
  }
  _buildGridView1(){
    return GridView(
      padding: EdgeInsets.zero,
      gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 120.0,
          childAspectRatio: 2.0 //宽高比为2
      ),
      children: const <Widget>[
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    );
  }
  _buildGridBuilderView(){
    return GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
          childAspectRatio: 1.0
        ),
        itemCount: _icons.length,
        itemBuilder: (context,index){
          //假如显现到最后一个而且Icon总数小于200时继续获取数据
          if(index == _icons.length-1 && _icons.length<200){
              _retrieveIcons();
          }
          return Icon(_icons[index]);
        });
  }
  _retrieveIcons(){
    Future.delayed(Duration(milliseconds: 200)).then((value){
      setState(() {
        _icons.addAll([
          Icons.ac_unit,
          Icons.airport_shuttle,
          Icons.all_inclusive,
          Icons.beach_access,
          Icons.cake,
          Icons.free_breakfast,
        ]);
      });
    });
  }
}
  • _retrieveIcons():在此办法中咱们经过Future.delayed来模拟从异步数据源获取数据,每次获取数据需求200毫秒,获取成功后将新数据添加到_icons,然后调用setState重新构建。
  • itemBuilder 中,假如显现到最后一个时,判别是否需求继续获取数据,然后返回一个Icon。 运转作用:

35、Flutter之GridView组件详解

GridView官方api文档:api.flutter-io.cn/flutter/wid…

35、Flutter之GridView组件详解