GridView inside a Listview causing "Vertical viewport was given unbounded height" even when Expanded

Viewed 5026

I'm still new to Flutter, and trying to create the following layout:

eLayout Of What I'm trying to achieve

I've split my layout into 3 main components:

  1. The Title widget (the one with "Title Here")
  2. The Info Text widget (the one with the Icon and "Info Goes Here" text)
  3. The GridView containing the buttons <--- This one is causing the problem

Here is my Main.dart:

import 'package:flutter/material.dart';
import 'package:ifp_poc/Screens/Home.dart';
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;

void main() {
//  debugPaintSizeEnabled = true;
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: new ThemeData(
        brightness: Brightness.light,
        primaryColor: Colors.blue,
        primaryColorLight: Colors.white,
        primaryColorDark: Colors.black,
        platform: Theme.of(context).platform,
      ),
      title: "POC",
      home: new Home(),
    );
  }
}

Here is my Home Class:

import 'package:flutter/material.dart';
import 'package:ifp_poc/Components/ifp/listBoxHQ.dart';
import 'package:ifp_poc/Components/ifp/infoHQ.dart';
import 'package:ifp_poc/Components/ifp/titleHQ.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: new Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          new TitleHQ(
            logoAsset: "assets/images/HQ-LOGO.png",
            title: "Hospitality Qatar",
            subTitle: "06-08 Nov 2018",
            info: "3:00 PM - 9:00 PM",
            url: "http://www.ifpexpo.com",
          ),
          new Container(
            padding: EdgeInsets.only(top: 15.0, left: 26.0, right: 26.0),
            child: new Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                new InfoHQ(text: "Qatar's Premiere International Hospitlaity & Horeca Trade Show",),
                new Divider(height: 20.0, color: Theme.of(context).primaryColorDark,),
                new InfoHQ(text: "Doha Exhibition & Convention Centre (DECC)",icon: Icons.location_on,),
                new Divider(height: 20.0, color: Theme.of(context).primaryColorDark,),
                new ListBoxHQ()
              ],
            ),
          )

        ],
      ),
    );
  }
}

Here is my listBoxHQ() Class:

import 'package:flutter/material.dart';
import 'package:ifp_poc/Components/ifp/boxHQ.dart';

class ListBoxHQ extends StatefulWidget {
  @override
  _ListBoxHQState createState() => _ListBoxHQState();
}

class _ListBoxHQState extends State<ListBoxHQ> {
  @override
  Widget build(BuildContext context) {

    return GridView.count(
          primary: false,
          crossAxisSpacing: 5.0,
          crossAxisCount: 3,
          children: <Widget>[
            BoxHQ(
              height: 100.0,
              text: "Overview",
              icon: Icons.ac_unit,
            ),
            BoxHQ(
              height: 100.0,
              text: "Overview",
              icon: Icons.ac_unit,
            ),
            BoxHQ(
              height: 100.0,
              text: "Overview",
              icon: Icons.ac_unit,
            ),
          ]
      );
  }
}

And Finally my BoxHQ Class:

import 'package:flutter/material.dart';

class BoxHQ extends StatefulWidget {
  final double height;
  final IconData icon;
  final String text;

  BoxHQ({Key key, @required this.height, @required this.icon, @required this.text}): super(key: key);

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

class _BoxHQState extends State<BoxHQ> {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: widget.height,
      width: double.infinity,
      padding: EdgeInsets.all(5.0),
      margin: EdgeInsets.all(7.0),
      decoration:  new BoxDecoration(
        borderRadius: new BorderRadius.all(const Radius.circular(10.0)),
        color: Colors.red,
      ),
      child: Column( // Replace with a Row for horizontal icon + text
        children: <Widget>[
          Icon(widget.icon == null? Icons.info : widget.icon, color: Theme.of(context).primaryColorLight, size: 50.0,),
          new Padding(padding: EdgeInsets.symmetric(vertical: 5.0)),
          Text(widget.text, style: new TextStyle(color: Theme.of(context).primaryColorLight, fontSize: 20.0),),
        ],
      ),
    );
  }
}

The Problem (TLDR) :

When running the above code, I get the following error:

I/Choreographer( 6979): Skipped 35 frames!  The application may be doing too much work on its main thread.
D/EGL_emulation( 6979): eglMakeCurrent: 0xa6cac080: ver 2 0 (tinfo 0x970aa0c0)
I/flutter ( 6979): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 6979): The following assertion was thrown during performResize():
I/flutter ( 6979): Vertical viewport was given unbounded height.
I/flutter ( 6979): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter ( 6979): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter ( 6979): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter ( 6979): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter ( 6979): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter ( 6979): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter ( 6979): the height of the viewport to the sum of the heights of its children.

Things I've tried and did not work:

  • Adding GridView.count from listBoxHQ class inside an Expanded
  • Adding every item of the Container from Home inside an Expanded
  • Adding every child of the main column of Home inside an Expanded

It worked only when I wrapped the GridView.count of listBoxHQ with a SizedBox and fixed height. But I can't do that as my buttons are dynamic and I don't know the number of buttons that I might have.

I can't thank you enough for reading through everything, and I will be very grateful if you could share your knowledge with me and help me fix this issue.

Thanks a lot, for real!

2 Answers

You should add this line of code inside your GridView:

shrinkWrap: true

So your GridView should looks like this:

return GridView.count(
  shrinkWrap: true,
  crossAxisCount: 3,
  children: <Widget>[
    BoxHQ(
      height: 100.0,
      text: "Overview",
      icon: Icons.ac_unit,
    ),
    BoxHQ(
      height: 100.0,
      text: "Overview",
      icon: Icons.ac_unit,
    ),
    BoxHQ(
      height: 100.0,
      text: "Overview",
      icon: Icons.ac_unit,
    ),
  ]
);

This value forces GridView to occupy as much space, as its' children do. By default, GridView wants to fill all available space to provide scrolling through children when they doesn't fit all at once. In your scenario, the GridView wants to take all available height but its parent, ListView doesn't specify how much is available. It's because ListView itself wants to scroll the children if they doesn't fit, thus they can be as big as they want.

In your GridView.count make shrinkWrap true.

......
return GridView.count(
    primary: false,
    shrinkWrap: true,
......
Related