How can I use a gridview inside a column?

2.1k Views Asked by At

I have a column with a container that acts as a header and a gridview of widgets below. I want only the gridview to be scrollable and that the header will not move and always be displayed.

This is my code:

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Container(
              margin: EdgeInsets.only(left: 24, right: 24),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(height: 22),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Message("Hello, Guest!", size: 32),
                      Icon(
                        CustomIcons.statistics,
                        color: AppColors.blue,
                        size: 32.0,
                      ),
                    ],
                  ),
                  SizedBox(height: 14),
                  Message("What worries you now? Select or Add.", size: 14),
                ],
              ),
            ),
            SizedBox(height: 16),
            GridView.count(
              primary: true,
              shrinkWrap: true,
              crossAxisCount: 2,
              crossAxisSpacing: 40.0,
              mainAxisSpacing: 40.0,
              padding: const EdgeInsets.all(20.0),
              children: _items,
            ),
          ],
        ),
      ),
    );
  }
}

When it runs I get a renderflex overflowed error: enter image description here

When I wrap my gridview in an expanded widget as some answers suggested, the scroll gets out of bounds: enter image description here

Appreciate the help!

4

There are 4 best solutions below

2
On

You need to use a combination of Stack, ListView and Column widgets. Here's how to do it:

return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            SizedBox(height: 16),
            ListView(
              shrinkWrap: true,
              children: [
                GridView.count(
                  primary: true,
                  shrinkWrap: true,
                  crossAxisCount: 2,
                  crossAxisSpacing: 40.0,
                  mainAxisSpacing: 40.0,
                  padding: const EdgeInsets.all(20.0),
                  children: [
                    Container(
                      margin: EdgeInsets.all(20),
                      color: Colors.red,
                      height: 200,
                      width: 200,
                    ),
                    Container(
                      margin: EdgeInsets.all(20),
                      color: Colors.amber,
                      height: 200,
                      width: 200,
                    ),
                    Container(
                      margin: EdgeInsets.all(20),
                      color: Colors.blue,
                      height: 200,
                      width: 200,
                    ),
                    Container(
                      margin: EdgeInsets.all(20),
                      color: Colors.green,
                      height: 200,
                      width: 200,
                    ),
                  ],
                ),
              ],
            ),
            Container(
              color: Colors.white,
              height: MediaQuery.of(context).size.height * 0.2,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(height: 22),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text("Hello, Guest!"),
                      Icon(
                        Icons.ac_unit,
                        color: Colors.blue,
                        size: 32.0,
                      ),
                    ],
                  ),
                  SizedBox(height: 14),
                  Text("What worries you now? Select or Add."),
                ],
              ),
            ),
          ],
        ),
      ),
    );
1
On

Remove expnaded and wrap your safe area With SingleChildScrollView, and also add phyiscs:ScrollPhysics() in gridview

1
On

Wrap your Column with a SingleChildScrollView, A Column will always try to shrink-wrap its children, using Expanded tells the GridView to only take up the available space.

Another alternative is if your GridView doesn't grow in too much size is to use the shrink-wrap: true and use physics: const NeverScrollablePhyscis(), that way the GridView won't try to grow to infinite size.

3
On

You can wrap your Column inside a SingleChildScrollView widget to make the whole column scrollable. The Code Should be :

class HomePage extends StatelessWidget {


const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child:Column(
          children: [
            Container(
              margin: EdgeInsets.only(left: 24, right: 24),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(height: 22),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Message("Hello, Guest!", size: 32),
                      Icon(
                        CustomIcons.statistics,
                        color: AppColors.blue,
                        size: 32.0,
                      ),
                    ],
                  ),
                  SizedBox(height: 14),
                  Message("What worries you now? Select or Add.", size: 14),
                ],
              ),
            ),
            SizedBox(height: 16),
            SingleChildScrollView(
              child: GridView.count(
              primary: true,
              shrinkWrap: true,
              crossAxisCount: 2,
              crossAxisSpacing: 40.0,
              mainAxisSpacing: 40.0,
              padding: const EdgeInsets.all(20.0),
              children: _items,
            ),
            ),
          ],
        ),
      ),
    );
  }
}