Why is Gridview.count not filling out the space with my dynamic content

Viewed 674

I am trying to create a gridview starting from the second column. The first card is just a static card with a button in it. So the second card starting should be dynamic.

All the cards have the same width and height. So basically they all should look like the first card (Add a new dog)

But it's not filling out the space as I expected it would.

enter image description here

Here is part of my code from the body section:

body: Stack(fit: StackFit.expand, children: [
      //bg image
      Container(
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage(Images.bgYellow), fit: BoxFit.cover)),
      ),
      //content
      SafeArea(
        bottom: false,
        left: true,
        right: true,
        top: false,
        child: Padding(
            padding: EdgeInsets.all(3 * SizeConfig.safeBlockHorizontal),
            child: GridView.count(
                    crossAxisCount: 2,
                    children: [
                      //add card
                      Container(
                        margin: EdgeInsets.symmetric(
                            vertical: 1 * SizeConfig.blockSizeVertical,
                            horizontal: 2 * SizeConfig.blockSizeHorizontal),
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(30),
                          color: Colors.white,
                          boxShadow: [
                            BoxShadow(
                              color: Colors.grey.withOpacity(0.5),
                              spreadRadius: 2,
                              blurRadius: 8,
                              offset: Offset(
                                  0, 2), // changes position of shadow
                            ),
                          ],
                        ),
                        child: FlatButton(
                            onPressed: null,
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Icon(
                                  const IconData(0xe901,
                                      fontFamily: 'icDog'),
                                  color: muddyBrown,
                                  size: 20 * SizeConfig.safeBlockHorizontal,
                                ),
                                SizedBox(height: 5),
                                Text(
                                  "ADD A NEW  DOG",
                                  style: TextStyle(
                                      color: muddyBrown,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 4 *
                                          SizeConfig.safeBlockHorizontal),
                                )
                              ],
                            )),
                      ),
                      //dynamic content
                      StateBuilder<PetState>(
                          observe: () => _petStateRM,
                          builder: (context, model) {
                            return Column(
                              children: [
                                ...model.state.pets.map((pet) =>
                                    GestureDetector(
                                      onTap: () {
                                        Navigator.pushNamed(
                                            context, petDetailRoute);
                                      },
                                      child: Container(
                                        margin: EdgeInsets.symmetric(
                                            vertical: 1 *
                                                SizeConfig
                                                    .blockSizeVertical,
                                            horizontal: 2 *
                                                SizeConfig
                                                    .blockSizeHorizontal),
                                        decoration: BoxDecoration(
                                          borderRadius:
                                              BorderRadius.circular(30),
                                          color: Colors.white,
                                          boxShadow: [
                                            BoxShadow(
                                              color: Colors.grey
                                                  .withOpacity(0.5),
                                              spreadRadius: 2,
                                              blurRadius: 8,
                                              offset: Offset(0,
                                                  2), // changes position of shadow
                                            ),
                                          ],
                                        ),
                                        child: Column(
                                          mainAxisAlignment:
                                              MainAxisAlignment.center,
                                          //dynamic data => Photo + Name
                                          children: [
                                            Container(
                                              width: 100.0,
                                              height: 100.0,
                                              decoration: new BoxDecoration(
                                                color:
                                                    const Color(0xff7c94b6),
                                                image: new DecorationImage(
                                                  image: new NetworkImage(
                                                      "${pet.photo}"),
                                                  fit: BoxFit.cover,
                                                ),
                                                borderRadius:
                                                    new BorderRadius.all(
                                                        new Radius.circular(
                                                            50.0)),
                                                border: new Border.all(
                                                  color: muddyBrown,
                                                  width: 4.0,
                                                ),
                                              ),
                                            ),
                                            SizedBox(height: 5),
                                            Text(
                                              "${pet.name}",
                                              style: TextStyle(
                                                  fontSize: 4 *
                                                      SizeConfig
                                                          .safeBlockHorizontal,
                                                  color: muddyBrown,
                                                  fontWeight:
                                                      FontWeight.bold),
                                            )
                                          ],
                                        ),
                                      ),
                                    ))
                              ],
                            );
                          }),
                    ],
                  )
                )),
    ]));
4 Answers

What about simply adding the 'static' card to the 'dynamic' ones and then build one GridView with all of them together?

Widget newDogButton = Card(...);

//dynamic content
StateBuilder<PetState>(
  observe: () => _petStateRM,
  builder: (context, model) {
    return Column(
      children: [
          newDogButton,
          ...model.state.pets.map((pet) =>  // ...

That should take care of most of your layout issues automatically.

Because StateBuilder return a widget. How about moving the Whole GridView inside it?

  ...
  child: Padding(
    padding: EdgeInsets.all(3 * SizeConfig.safeBlockHorizontal),
    child: StateBuilder<PetState>(
      observe: () => _petStateRM,
      builder: (context, model) {
        return GridView.count(
          crossAxisCount: 2,
          children: [

            // The button "ADD A NEW  DOG" here,
            Container(...),

            //dynamic content here
            ...model.state.pets.map((pet) =>

              ...

            ).toList(),

      },
    ),
  ),

Every grid item in GridView will have same height and width, if you want different dynamic height or width for different items, use flutter_staggered_grid_view, in your case:

StaggeredGridView.countBuilder(
  crossAxisCount: 2,
  itemCount: 2,
  itemBuilder: (BuildContext context, int index) => new Container(
      color: Colors.green,
      child: new Center(
        child: new CircleAvatar(
          backgroundColor: Colors.white,
          child: new Text('$index'),
        ),
      )),
  staggeredTileBuilder: (int index) =>
      new StaggeredTile.count(1, index.isEven ? 2 : 1),
  mainAxisSpacing: 4.0,
  crossAxisSpacing: 4.0,
)

The situation:
To me, this problem is not coming from your Dynamic content but from the height allowed to it to display it's content. Inside the GridView.count constructor, the default childAspectRatio value is 1.0, meaning that the default max height of each child of the GridView is deviceWidth / crossAxisCount (2 in your case).

The problem:
In order for each child to display correctly, it's height must not exceed this ratio (causing your overflowed error).

My opinion:
To solve this problem, I will either replace the dynamic content StateBuilder<PetState> with a static Widget which height will not exceed the ratio OR wrap the dynamic content StateBuilder<PetState> in a SingleChildScrollView to ensure that the overflowed error will not happen and the wrapper can produce the scroll effect to see the entire dynamic content.

Related