GridView inside a Container inside a Column doesn't fill up the rest of the screen

Viewed 1837

The short version:

GridView without enough items inside a Container doesn't fill up the rest of the screen.

Bad result, not enough items With many items

The long version:

My flutter app has a Column that should be scrollable, the Column has the following children:

  • Container with an Image
  • A SizedBox for spacing
  • A Container with a GridView (for styling)

If the items inside my GridView are not enough, the color of the container (that contains the GridView) doesn't get applied to the end of the screen.

This my code structure:

return Scaffold(
      backgroundColor: Color(0xFF0f2447),
      body: Container(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              // First Column Item
              Container(
                height: 250,
                decoration: BoxDecoration(
                  image: DecorationImage(
                    image: AssetImage('assets/images/ise.png'),
                    fit: BoxFit.cover,
                  ),
                ),
                child: Container(
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.bottomLeft,
                      colors: [
                        Colors.black.withOpacity(0.0),
                        Colors.black.withOpacity(0.2),
                      ],
                    ),
                  ),
                ),
              ),
              // Second Column Item
              SizedBox(
                height: 20,
              ),
              // Third Column Item
              Container(
                // What I have tried
                // height: double.infinity, (Error: BoxConstraints forces an infinite height.)
                // height: 500, (Works, but depends on the device height (can't be static) )
                // height: "the remaining height of the screen whatever it is"
                margin: EdgeInsets.only(left: 10, right: 10),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(50),
                    topRight: Radius.circular(50),
                  ),
                ),
                child: GridView.count(
                  physics: BouncingScrollPhysics(),
                  shrinkWrap: true,
                  crossAxisCount: 3,
                  children: currentList
                      .map(
                        (item) => ItemIcon(
                          label: item['title'],
                          icon: AssetImage(item['iconPath']),
                          changeView: changeView,
                          itemId: item['itemId'],
                        ),
                      )
                      .toList(),
                ),
              ),
            ],
          ),
        ),
      ),
    );

ItemIcon is a custom widget, it has an image with a fixed size and a Text with some padding.

Current list is simply as follows: (Just to avoid long code)

final List<Map<String, Object>> examples = [
 {
    'title': 'Test',
    'itemId': 0,
    'iconPath': 'assets/icons/icon.png',
 },
 ...
]

Apologies for the confusing title.

1 Answers

Try to wrap the third container in Expanded class, and it will do your job.

Expanded takes up the remaining spaces in Row/Column.

Code

        Expanded(
           child: Container(
                // What I have tried
                // height: double.infinity, (Error: BoxConstraints forces an infinite height.)
                // height: 500, (Works, but depends on the device height (can't be static) )
                // height: "the remaining height of the screen whatever it is"
                margin: EdgeInsets.only(left: 10, right: 10),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(50),
                    topRight: Radius.circular(50),
                  ),
                ),
                child: GridView.count(
                  physics: BouncingScrollPhysics(),
                  shrinkWrap: true,
                  crossAxisCount: 3,
                  children: currentList
                      .map(
                        (item) => ItemIcon(
                          label: item['title'],
                          icon: AssetImage(item['iconPath']),
                          changeView: changeView,
                          itemId: item['itemId'],
                        ),
                      )
                      .toList(),
                ),
              ) 
        )

Alternative

You can anyway rely on the previous code, and just play with the height using MediaQuery class. This will keep the height uniformed to different device

              Container(
                // play with the floating number to get the desired height
                height: MediaQuery.of(context).size.height * 0.61,
                margin: EdgeInsets.only(left: 10, right: 10),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(50),
                    topRight: Radius.circular(50),
                  ),
                ),
                child: GridView.count(
                  physics: BouncingScrollPhysics(),
                  shrinkWrap: true,
                  crossAxisCount: 3,
                  children: currentList
                      .map(
                        (item) => ItemIcon(
                          label: item['title'],
                          icon: AssetImage(item['iconPath']),
                          changeView: changeView,
                          itemId: item['itemId'],
                        ),
                      )
                      .toList(),
                ),
              )

Another Workaround for Landscape view

You can use Stack class for achieving uniformity. Make use of the third widget as is. Just use the Stack to align the items for your landscape view. Please read about Positioned class, which help you align your items in the view

So the view will be

Stack(
  Container with an Image
  // the last one comes on top of the first view
  // no sizedbox required since you can align the item using Positioned
  Positioned(
    top: use media_query_dimension,
    left: use media_query_dimension,
    right: use media_query_dimension, 
    bottom: use media_query_dimension.
    child: A Container with a GridView (for styling)
  )
)
Related