1
votes

I'm converting my native android project in to flutter application, in this i need to display grid of options below other widgets.

here is code

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Column homeThumb(String icon, String label) {
      Color color = Theme.of(context).primaryColor;

      return new Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          new Container(
            margin: const EdgeInsets.all(8.0),
            child: new Image.asset(icon, width: 32.0, height: 32.0),
          ),
          new Container(
            margin: const EdgeInsets.only(top: 8.0),
            child: new Text(
              label,
              textAlign: TextAlign.center,
              style: new TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: color,
              ),
            ),
          ),
        ],
      );
    }

    Widget homeIcon = new Container(
        child: new Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
          new Container(
              margin: const EdgeInsets.only(
                  top: 40.0, left: 8.0, right: 8.0, bottom: 8.0),
              child: new Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  homeThumb("images/icons/list.png", 'Claim Offers'),
                  homeThumb("images/icons/wallet.png", 'Wallet'),
                  homeThumb("images/icons/cart.png", 'Redeem Offers'),
                ],
              )),
          new Container(
              margin: const EdgeInsets.all(8.0),
              child: new Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  homeThumb("images/icons/user.png", 'Account'),
                  homeThumb("images/icons/badge.png", 'Merchants'),
                  homeThumb("images/icons/history.png", 'Shopping History'),
                ],
              )),
          new Container(
              margin: const EdgeInsets.all(8.0),
              child: new Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  homeThumb("images/icons/bell.png", 'Notifications'),
                  homeThumb("images/icons/plane.png", 'Service Request'),
                  homeThumb("images/icons/share.png", 'Share & Earn'),
                ],
              )),


        ]));

    Widget grid = new GridView.count(
      crossAxisCount: 4,
      children: new List<Widget>.generate(16, (index) {
        return new GridTile(
          child: new Card(
              color: Colors.blue.shade200,
              child: new Center(
                child: new Text('tile $index'),
              )
          ),
        );
      }),
    );

    return new MaterialApp(
      title: 'Minkville',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Minkville'),
        ),
        body: new ListView(
          children: [
            new Image.asset(
              'images/slider/img_s1.jpg',
              width: 600.0,
              height: 180.0,
              fit: BoxFit.fill,
            ),
            homeIcon,
            grid

          ],
        ),
      ),
    );
  }
}

on debug, following logs are coming

I/flutter (16594): Another exception was thrown: 'package:flutter/src/rendering/sliver_multi_box_adaptor.dart': Failed assertion: line 441 pos 12: 'child.hasSize': is not true. I/flutter (16594): Another exception was thrown: RenderBox was not laid out: RenderRepaintBoundary#199e9 relayoutBoundary=up3 NEEDS-PAINT

4
Take a look over here at my answer stackoverflow.com/questions/50095763/…Muhammad Adil

4 Answers

3
votes

Ignore all the above answers. Make sure you set shrinkWrap : true in both ListView and GridView. Problem Solved!!

1
votes

My simplest example no CustomScrollView no SilverGrid just a normal ListView and GridView. Heres Why I think you cant directly put a gridView inside a ListView because once you do that

  • you cant differentiate whether you are scrolling a list or a grid because both are scrollable.
  • ListView takes a widget and since it is scrollable it must require widgets of a defined height

so the work around here is to give it a widget of a specific height so if you give it a container of a specific height and add a grid view inside a container then this should do your job

List<MaterialColor> gridColors = [
  Colors.red,
  Colors.deepPurple,
  Colors.green,
  Colors.deepOrange,
  Colors.red,
  Colors.deepPurple,
  Colors.green,
  Colors.deepOrange,
  Colors.red,
  Colors.deepPurple,
  Colors.green,
  Colors.deepOrange
];



  static Widget body() {
    return ListView(
      children: <Widget>[
        Container(
          height: 400,
          color: Colors.green,
        ),
        Container(
          height: 400,
          color: Colors.deepOrangeAccent,
          child: GridView.builder(
              gridDelegate:
                  SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
              itemCount: 8,
              itemBuilder: (BuildContext context, int x) {
                return Container(
                  margin: EdgeInsets.all(10),
                  height: 100,
                  width: 100,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    color: gridColors[x],
                  ),
                );
              }),
        ),
        Container(
          height: 400,
          color: Colors.blue,
        ),
      ],
    );
  }

heres the output hope it helps someone

enter image description here

0
votes

You need to wrap the GridView into an Expanded widget. More about that here.

0
votes

1. Identify Problem

new ListView(
  children: [
    new Image.asset(
      'images/slider/img_s1.jpg',
      width: 600.0,
      height: 180.0,
      fit: BoxFit.fill,
    ),
    homeIcon,
    grid // this is the problem
  ],
),

the problem is here. because the grid is defined as GridView Widget, Flutter cannot renders it as children of ListView.

Widget grid = GridView.count(
      crossAxisCount: 4,
...

2. But I want the screen to be scrollable as well?

To do that, we need to replace SingleChildScrollView or similar widget, e.g ListView. We change it into CustomScrollView.

This is necessary because actually, Flutter recognizes two patterns :

  • List View pattern children will be added in the vertical direction

  • Grid Box pattern children will be added in the Z direction. If it has two-column, its 1st and 2nd children will be rendered on First Row. then its second-row rendered with 3rd and 4th.

Official Docs

CustomScroll

3. How to write that section?

body: CustomScrollView( // replacement of SingleScrollChildView
  slivers: <Widget>[ // rather than children, it is named slivers
    // List Pattern section
    SliverList( // replacement of ListView
      delegate : // rather than children, it is named delegate
      ...
    ),
    // Grid Pattern section
    SliverGrid(
      delegate : // rather than children, it is named delegate
      ...
    ),

  ],
)

4. Final Code

  • Changed ListView to SliverList to make a List Section
  • Wrap it with CustomScrollView
  • Put SliverGrid below SliverList, which is our Grid Section
  • Render our grid variable, inside SliverGrid
body: new ListView( // replace this to SliverList
  children: [
    new Image.asset(
      'images/slider/img_s1.jpg',
      width: 600.0,
      height: 180.0,
      fit: BoxFit.fill,
    ),
    homeIcon,
    grid // needs to be moved into our Grid Section 

  ],
),
body: CustomScrollView(
  slivers: <Widget>[
    // A. This is our List Section
    SliverList(
      delegate: SliverChildListDelegate([
        Image.asset(
          'images/slider/img_s1.jpg',
          width: 600.0,
          height: 180.0,
          fit: BoxFit.fill,
        ),
        homeIcon,
        // grid
      ]),
    ),
    // B. This is our Grid Section
    SliverGrid.count(
      children: <Widget>[grid],
      crossAxisCount: 1,
    ),
  ],
),

Demo

Demo

You may bundle it yourself by using this repo Github