Search code examples
fluttergridviewflutter-card

Flutter Card child content height is larger than its parent


I'm trying to use a GridView to handle displays for multiple Card, each Card contains of an Image. Unfortunately it turns out that the Image is taking a larger height than its parent (see attached picture for the details).

I'm pretty new to Flutter layout so any ideas why this is happening and how I can resolve this? I want the layout to be something like this:

  • Display 2 cards on each line.
  • The Card width or height should not be fixed.
  • The Image height should be scaled according to its width.

enter image description here

class SquadSelectionScreen extends StatelessWidget {
  final List<Team> teams;

  const SquadSelectionScreen({super.key, required this.teams});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Squads'),
      ),
      body: GridView.count(
        crossAxisSpacing: 10,
        crossAxisCount: 2,
        padding: const EdgeInsets.all(16),
        children: teams
            .map(
              (team) => SquadView(team: team),
            )
            .toList(),
      ),
    );
  }
}

class SquadView extends StatelessWidget {
  final Team team;

  const SquadView({super.key, required this.team});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        context.push('/squads/${team.code}');
      },
      child: Card(
        elevation: 1,
        child: Column(
          children: [
            Image(
              image: NetworkImage(team.imageUrl),
            ),
            const SizedBox(
              height: 8,
            ),
            Center(
              child: Text(team.name),
            ),
          ],
        ),
      ),
    );
  }
}

Solution

  • Using GridView.count has a very visible drawback, namely the size of the aspect ratio of the grid will always be one (1:1 or Square) and can't be changed.

    So if you look at the code above, you can't set an image with the same aspect ratio because the text will sink.

    The first suggestion for me if you still want to use GridView.count is

    1. Wrapping your Image with AspectRatio that has value higher than one (example set Ratio to 4/3, 5/3, 16/9, or landscape looks). Note: 4/3 = is higher than 1, 16/9 = is higher than 1, etc..

    2. Then wrap the Text Widget with Expanded()

    Example code:

    class SquadView extends StatelessWidget {
      final Team team;
    
      const SquadView({super.key, required this.team});
    
      @override
      Widget build(BuildContext context) {
        return InkWell(
          onTap: () {},
          child: Card(
            elevation: 1,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: [
                  AspectRatio(
                    aspectRatio: 4/3, // you can set the value to 16/9 or anything that result is higher than one
                    child: Image(
                      image: NetworkImage(team.imageUrl),
                      fit: BoxFit.cover, // set How the image looks to Fit
                    ),
                  ),
                  const SizedBox(
                    height: 8,
                  ),
                  Expanded(
                    child: Center(
                      child: Text(team.name, overflow: TextOverflow.ellipsis),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    I suggest you try GridView.builder or another GridView. You can look at the documentation here

    or this third package this will be good for to try flutter_staggered_grid_view. The flutter_staggered_grid_view is more flexible to create GridView with various size.