42. Detailed explanation of GridView component of fluent

Posted by statrat on Sat, 22 Jan 2022 07:18:54 +0100

GridView

GridView can build a two-dimensional grid list, and its default constructor is defined as follows:

  GridView({
    Key? key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController? controller,
    bool? primary,
    ScrollPhysics? physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry? padding,
    required this.gridDelegate,  //Explain below
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    double? cacheExtent, 
    List<Widget> children = const <Widget>[],
    ...
  })

We can see that most parameters of GridView and ListView are the same, and their meanings are the same. If you have doubts, you can refer to the ListView section, which will not be repeated here. The only thing we need to pay attention to is the gridDelegate parameter. The type is slicergriddelegate. Its function is to control how the GridView sub components are arranged.

Slicergriddelegate is an abstract class that defines GridView Layout related interfaces. Subclasses need to implement them to implement specific layout algorithms. Flutter provides two subclasses of SliverGridDelegateWithFixedCrossAxisCount and SliverGridDelegateWithMaxCrossAxisExtent, which can be used directly. Let's introduce them respectively below.

SliverGridDelegateWithFixedCrossAxisCount

This subclass implements a layout algorithm whose horizontal axis is a fixed number of sub elements, and its constructor is:

SliverGridDelegateWithFixedCrossAxisCount({
  @required double crossAxisCount, 
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • crossAxisCount: number of cross axis child elements. After this attribute value is determined, the length of the child element on the horizontal axis is determined, that is, the quotient of the horizontal axis length of the ViewPort divided by the crossAxisCount.
  • mainAxisSpacing: spacing in the spindle direction.
  • crossAxisSpacing: the spacing of child elements in the horizontal axis direction.
  • childAspectRatio: the ratio of child elements in the length of the horizontal axis to the length of the main axis. After crossAxisCount is specified, the horizontal axis length of the child element is determined, and then the length of the child element in the spindle can be determined through this parameter value.

It can be found that the size of the child element is determined by the two parameters crossAxisCount and childAspectRatio. Note that the sub element here refers to the maximum display space of the sub component. Be careful to ensure that the actual size of the sub component does not exceed the space of the sub element.

Here is an example:

GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,//Horizontal axis three sub widget s
          childAspectRatio: 1.0,//Width height ratio of child 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)
      ],
    )

 

GridView.count

GridView. The count constructor internally uses SliverGridDelegateWithFixedCrossAxisCount, which allows us to quickly create GridViews with a fixed number of child elements on the horizontal axis. The above example code is equivalent to:

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

This subclass implements a layout algorithm with a fixed maximum length of horizontal axis sub elements, and its constructor is:

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

maxCrossAxisExtent is the maximum length of the child element on the horizontal axis. It is the "maximum" length because the length of each child element in the horizontal axis direction is still equally divided. For example, if the horizontal axis length of the ViewPort is 450, Then, when the value of maxCrossAxisExtent is within the interval [450 / 4450 / 3), the final actual length of the child element is 112.5, and the length ratio of the horizontal axis and the main axis of the child element referred to by childAspectRatio is the final length ratio. Other parameters are the same as SliverGridDelegateWithFixedCrossAxisCount.

Let's take an example:

GridView(
  padding: EdgeInsets.zero,
  gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 120.0,
      childAspectRatio: 2.0 //The aspect ratio is 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),
  ],
);

 

GridView.extent

GridView. The extension constructor uses the slicergriddelegatewithmaxcrossaxisextent internally. Through it, we can quickly create a GridView with a fixed maximum length of the vertical axis sub element. The above example code is equivalent to:

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

The GridView described above requires a widget array as its child elements. These methods will build all child widgets in advance, so they are only applicable to the case where the number of child widgets is relatively small, and when the number of child widgets is relatively large, we can use GridView Builder to dynamically create child widgets. GridView. The builder must specify two parameters:

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

Where itemBuilder is the child widget builder.

Suppose we need to obtain some icons from an asynchronous data source (such as network) in batches, and then use GridView to display:

import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';

/// @Author wywinstonwy
///@ Date 2022/1/21 8:48 am
/// @Description: 

class MyGridViewPage extends StatefulWidget {
  const MyGridViewPage({Key? key}) : super(key: key);

  @override
  _MyGridViewPageState createState() => _MyGridViewPageState();
}

class _MyGridViewPageState extends State<MyGridViewPage> {
  List<IconData> _icons = []; //Save Icon data

  @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,//Horizontal axis three sub widget s
          childAspectRatio: 1.0,//Width height ratio of child 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 //The aspect ratio is 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){
          //If the last one is displayed and the total number of icons is less than 200, continue to obtain data
          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(): in this method, we use future Delayed to simulate obtaining data from an asynchronous data source. It takes 200 milliseconds to obtain data each time. After successful acquisition, new data is added to the database_ icons, and then call setState to rebuild.
  • In itemBuilder, if the last one is displayed, judge whether to continue to obtain data, and then return an Icon.

effect:

demo complete code: flutter_ Demo: fluent component test learning demo

Topics: iOS Android Android Studio Flutter