• 【Flutter】可滚动组件之GridView


    前言

    GridView可以构建一个二维网格列表。需要关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout)。SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent。

    接口描述

    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,
      })
    
    const SliverGridDelegateWithFixedCrossAxisCount({
        @required this.crossAxisCount,
        // 主轴方向的间距
        this.mainAxisSpacing = 0.0,
        // 横轴方向子元素的间距
        this.crossAxisSpacing = 0.0,
        // 子元素在横轴长度和主轴长度的比例
        this.childAspectRatio = 1.0,
      })
    
    const SliverGridDelegateWithMaxCrossAxisExtent({
        // 为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的
        @required this.maxCrossAxisExtent,
        this.mainAxisSpacing = 0.0,
        this.crossAxisSpacing = 0.0,
        // 所指的子元素横轴和主轴的长度比为最终的长度比
        this.childAspectRatio = 1.0,
      })
    
    

    代码示例

    // GridView
    
    // GridView可以构建一个二维网格列表。需要关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout)。
    // SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。
    // Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent。
    
    // SliverGridDelegateWithFixedCrossAxisCount
    import 'package:flutter/material.dart';
    
    class GridViewTest1 extends StatelessWidget{
      @override
      Widget build(BuildContext context){
        return Scaffold(
          appBar: AppBar(
            title: Text('SliverGridDelegateWithFixedCrossAxisCount'),
          ),
          body: GridView(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              // 横轴三个子widget
              crossAxisCount: 3,
              // 宽高比为1时,子widget
              childAspectRatio: 1.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)
            ],
          ),
    
          // 等价于
    
    //      body: GridView.count(
    //        crossAxisCount: 3,
    //        childAspectRatio: 1.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),
    //        ],
    //      )
    
        );
      }
    }
    
    // SliverGridDelegateWithMaxCrossAxisExtent
    class GridViewTest2 extends StatelessWidget{
      @override
      Widget build(BuildContext context){
        return Scaffold(
          appBar: AppBar(
            title: Text('SliverGridDelegateWithMaxCrossAxisExtent'),
          ),
          body: GridView(
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              // 元素在横轴上的最大长度
              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)
            ],
          ),
    
          // 等价于
    
    //      body: 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
    // 从一个异步数据源(如网络)分批获取一些Icon
    class InfiniteGridView extends StatefulWidget{
      @override
      _InfiniteGridViewState createState() => _InfiniteGridViewState();
    }
    
    class _InfiniteGridViewState extends State<InfiniteGridView>{
      // 保存Icon数据
      List<IconData> _icons = [];
    
      @override
      void initState(){
        // 初始化数据
        _retrieveIcons();
      }
    
      @override
      Widget build(BuildContext context){
    
        return Scaffold(
          appBar: AppBar(
            title: Text(''),
          ),
          body: GridView.builder(
              gridDelegate: 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]);
              }
          ),
        );
      }
    
      // 模拟异步获取数据
      void _retrieveIcons(){
        Future.delayed(Duration(milliseconds: 200)).then((e){
          setState(() {
            _icons.addAll([
              Icons.ac_unit,
              Icons.airport_shuttle,
              Icons.all_inclusive,
              Icons.beach_access,
              Icons.free_breakfast,
            ]);
          });
        });
      }
    
    }
    
    
    

    总结

    在实际开发中,可能会遇到子元素大小不等的情况,Pub上有一个包“flutter_staggered_grid_view” ,它实现了一个交错GridView的布局模型,可以很轻松的实现这种布局。

  • 相关阅读:
    C#的GroupBy方法是如何工作的
    流媒体技术探索(一)
    战争雷霆-鼠标穿透
    继承与ER图
    从零开始的文档对象模型(结束更新)
    [hackerrank] booking.com
    [lintcode][美国大公司][1.字符串处理]
    [interview] Aug. 2015
    [codility] Lesson 2 Counting Elements
    [codility] Lesson 1 Time Complexity
  • 原文地址:https://www.cnblogs.com/parzulpan/p/12193936.html
Copyright © 2020-2023  润新知