56

I'd like to build design like Ios app store like image below. What I'm trying to achieve is there are 5 top category and each category has grid that shows images. And I tried like this.

like this

return new Scaffold(
  backgroundColor: Colors.white,
  appBar: buildBar(context),
  // wrap in gesture to dismiss keyboard
  body: new GestureDetector(
    behavior: HitTestBehavior.opaque,
    onPanDown: (detail) {
      FocusScope.of(context).requestFocus(new FocusNode());
    },
    child: new ListView(
      shrinkWrap: true,
      children: <Widget>[
        new Container(
          decoration: new BoxDecoration(color: Colors.grey[400]),
          child: new Column(
            children: <Widget>[
              new SizedBox(height: 15.0),
              new Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new Icon(Icons.invert_colors,
                      color: Colors.red, size: 45.0),
                  new Text('Top 5',
                      style: new TextStyle(
                          color: Colors.white,
                          fontSize: 25.0,
                          fontWeight: FontWeight.bold)),
                ],
              ),
              new SizedBox(height: 15.0),
            ],
          ),
        ),
        new SizedBox(height: 30.0),
        new ListView.builder(
          shrinkWrap: true,
          itemCount: 5,
          itemBuilder: (BuildContext context, int index) {
            return new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Container(
                  decoration:
                      new BoxDecoration(color: Colors.lightBlue[200]),
                  child: new Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      new Icon(icons[index],
                          size: 30.0),
                      new Padding(
                          padding: const EdgeInsets.only(right: 5.0)),
                      new Text('Category',
                          style: new TextStyle(
                              fontSize: 23.0, fontWeight: FontWeight.bold)),
                    ],
                  ),
                ),
                new SizedBox(height: 5.0),
                new GridView.builder(
                  shrinkWrap: true,
                  scrollDirection: Axis.horizontal,
                  itemCount: 10,
                  gridDelegate:
                      new SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: 4),
                  itemBuilder: (BuildContext context, int index) {
                    return new GestureDetector(
                        child: new Card(
                          elevation: 5.0,
                          child: new Container(
                            padding: new EdgeInsets.only(
                                bottom: 2.0, right: 3.0),
                            decoration: new BoxDecoration(
                              image: new DecorationImage(
                                fit: BoxFit.cover,
                                image: NetworkImage(
                                    'https://images.unsplash.com/photo-1505535162959-9bbcb4ab22d6?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0891a99609bf6fdc48842101bef90d67&auto=format&fit=crop&w=500&q=60'),
                              ),
                            ),
                          ),
                        ),
                        onTap: () {
                          print('tapped');
                        });
                  },
                ),
                new SizedBox(height: 20.0),
              ],
            );
          },
        ),
      ],
    ),
  ),
);

But grid view doesn't appear and if I commented out grid view then shows list that doesn't have images just category names. I tried to wrap expanded, set shrinkWrap to true but did not working. I've been searching through but still can't figure it out. Anyone know how to fix it?

EDIT:

 return new Scaffold(
  backgroundColor: Colors.white,
  appBar: new AppBar(
    title: new Text('Search'),
  ),
  body: new GestureDetector(
    behavior: HitTestBehavior.opaque,
    onPanDown: (detail) {
      print(detail);
      FocusScope.of(context).requestFocus(new FocusNode());
    },
    child: new ListView(
      shrinkWrap: true,
      children: <Widget>[
        new SizedBox(height: 20.0),
        new Container(
            height: 60.0,
            color: Colors.blue,
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Icon(Icons.hourglass_empty,
                    color: Colors.white, size: 30.0),
                new Padding(padding: const EdgeInsets.only(right: 5.0)),
                new Text('TOP5',
                    style:
                        new TextStyle(color: Colors.white, fontSize: 23.0)),
              ],
            ),
          ),
          new SizedBox(height: 20.0),
        new Container(
          child: new ListView.builder(
            shrinkWrap: true,
            itemCount: 5,
            itemBuilder: (context, index) {
              return new Column(
                children: <Widget>[
                  new Container(
                    height: 50.0,
                    color: Colors.green,
                    child: new Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        new Icon(Icons.format_list_numbered,
                            color: Colors.white),
                        new Padding(
                            padding: const EdgeInsets.only(right: 5.0)),
                        new Text(arr[index],
                            style: new TextStyle(
                                fontSize: 20.0, color: Colors.white)),
                      ],
                    ),
                  ),
                  new Container(
                    height: 150.0,
                    child: new ListView.builder(
                      shrinkWrap: true,
                      scrollDirection: Axis.horizontal,
                      itemCount: 10,
                      itemBuilder: (context, index) {
                        return new GestureDetector(
                          child: new Card(
                            elevation: 5.0,
                            child: new Container(
                              height: MediaQuery.of(context).size.width / 3,
                              width: MediaQuery.of(context).size.width / 3,
                              alignment: Alignment.center,
                              child: new Text('Item $index'),
                            ),
                          ),
                          onTap: () {
                            print(123);
                          },
                        );
                      },
                    ),
                  ),
                  new SizedBox(height: 20.0),
                ],
              );
            },
          ),
        ),
      ],
    ),
  ),
);

enter image description here

0

7 Answers 7

111

I have used a flutter GridView inside a ListView, both are vertical scrolling:

body: ListView(
  children: <Widget>[
    GridView.count(
      crossAxisCount: 3,
      physics: NeverScrollableScrollPhysics(), // to disable GridView's scrolling
      shrinkWrap: true, // You won't see infinite size error
      children: <Widget>[
        Container(
          height: 24,
          color: Colors.green,
        ),
        Container(
          height: 24,
          color: Colors.blue,
        ),
      ],
    ),
    // ...... other list children. 
  ],
),

You can use same approach for flutter horizontal ListView/GridView inside another ListView.

Sign up to request clarification or add additional context in comments.

3 Comments

I cannot drag/scroll the ListView when touching/dragging elements in the GridView when using this solution. I.e. if I have a GridView that is large enough to fill the screen, I cannot scroll the ListView at all any more. I have found that this can be fixed by adding "physics: ScrollPhysics()" to the GridView.
yes and this will stop scrolling of GridView. and enable listview to scroll. You can do one more thing that is Use of CustomScrollView and inside that CustomScrollView you can use SliverGridView and SliverListView. Well i have updated my answer.
don't forget to add shrinkWrap:true along with scrollphysics ,because if you directly add gridView inside listview then it will throw error since it cant detect where the gridview will end.even though shrinkwrap is expensive since it computes the size of the grid on scroll,but it solve s the problem
28

You can try to use Horizontal scrolling lists inside a vertical scrolling list to achieve this type of layout easily.

In your horizontal list and vertical list put

shrinkWrap : true

Or

Wrap the lists inside an Expanded() widget

EDIT

This is how I used a List view inside another list view.

                     Container ( child : 
                        ListView.builder(
                            itemBuilder: (context, subMenuIndex) {
                              return Container(
                                padding: EdgeInsets.only(left: 20.0),
                                child: sideMenuStuff.sideMenuData.elementAt(mainIndex).menu.subMenu.elementAt(subMenuIndex).subSubMenu != null
                                    ? ExpansionTile(
                                  title: Text(sideMenuStuff.sideMenuData.elementAt(mainIndex).menu.subMenu.elementAt(subMenuIndex).zero.info.title,
                                  ),
                                  children: <Widget>[
                                    ListView.builder(
                                        shrinkWrap: true,
                                        itemCount: sideMenuStuff.sideMenuData.elementAt(mainIndex).menu.subMenu.elementAt(subMenuIndex).subSubMenu.length,                                     
                                        itemBuilder:
                                            (context, subSubMenuIndex) {
                                          return Container(
                                            padding: EdgeInsets.only(
                                                left: 40.0,
                                                top: 10.0,
                                                bottom: 10.0),
                                            child:
                                            GestureDetector(
                                              onTap:
                                                  () {
                                                Navigator
                                                    .pop(context);
                                                Navigator
                                                    .of(context)
                                                    .push(MaterialPageRoute(
                                                    builder: (context) =>
                                                        Products(
                                                            sideMenuStuff
                                                                .sideMenuData
                                                                .elementAt(
                                                                mainIndex)
                                                                .menu
                          ....
                          ....
                          );

9 Comments

thank you for the answer and I changed gridview to horizontal listview but still gives me error says Horizontal viewport was given unbounded height can you tell what is wrong?
Thank you again but now gives me this Incorrect use of ParentDataWidget. Expanded widgets must be placed inside Flex widgets Where should I put Expanded? Because I have listview and under that I have listview and under that I have horizontal listview.
I just tried wrap parent listview which is first listview but still nothing shows up.
I’ll post a code sample for you for better understandings
Thanks to your code, I was able to show what I wanted but if I scroll down I should see the number 5 category. but I can't see the 5 like the picture above(I edited). I wrapped every widget but as I scroll down "TOP5" doesn't disappear. Does this make sense to you? How can I fix it?
|
21

when I used

 GridView.count(
      shrinkWrap: true,
      crossAxisCount: 2,
      physics: ScrollPhysics(),

the physics property , it worked with me

Comments

8

You shouldn't use shrikWrap in customScrollView. This code is recomended to create any list inside customSrollView:


  @override
  Widget build(BuildContext context) => Scaffold(
      body: CustomScrollView(slivers: [
            //custom widget
            SliverToBoxAdapter(child: YourContainer()),
            //horizontal list
            SliverToBoxAdapter(child: Container(
                  height: 55,
                  child: ListView.builder(
                      scrollDirection: Axis.horizontal,
                      itemCount: 10,
                      itemBuilder: (context, index) {
                        return YourItem();
                      })))
            ])),
            //grid list
            SliverGrid(
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2, mainAxisSpacing: 0, crossAxisSpacing: 0),
                delegate: SliverChildListDelegate(
                    List.generate(10, (index) => YourAnotherItem())))
          ]));

I hope this is useful.

1 Comment

should be the accepted answer. other solutions also work but could be rendered all grid items & cause memory bugs
3

physics: ScrollPhysics(), will do the trick if ListView/GridView not Scrolling, This may happen if Parent Widget is SingleChildScrollView or ListView/GridView which provide scrolling functionality to Parent Widget, not to Child Widget.

Solution:

Scaffold(
      backgroundColor: Colors.white,
      appBar: new AppBar(
        title: new Text('Search'),
      ),
      body: new ListView(
        shrinkWrap: true,
        physics: ScrollPhysics(),
        children: <Widget>[
          new SizedBox(height: 20.0),
          new Container(
            child: new ListView.builder(
              shrinkWrap: true,
              itemCount: 5,
              physics: ScrollPhysics(),
              itemBuilder: (context, index) {
                return new Column(
                  children: <Widget>[
                    new Container(
                      height: 50.0,
                      color: Colors.green,
                      child: new Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          new Icon(Icons.format_list_numbered,
                              color: Colors.white),
                          new Padding(
                              padding: const EdgeInsets.only(right: 5.0)),
                          new Text('List Item',
                              style: new TextStyle(
                                  fontSize: 20.0, color: Colors.white)),
                        ],
                      ),
                    ),
                    new Container(
                      height: 150.0,
                      child: new ListView.builder(
                        shrinkWrap: true,
                        scrollDirection: Axis.horizontal,
                        itemCount: 10,
                        itemBuilder: (context, index) {
                          return new Card(
                            elevation: 5.0,
                            child: new Container(
                              height: MediaQuery.of(context).size.width / 3,
                              width: MediaQuery.of(context).size.width / 3,
                              alignment: Alignment.center,
                              child: new Text('Item $index'),
                            ),
                          );
                        },
                      ),
                    ),
                    new SizedBox(height: 20.0),
                  ],
                );
              },
            ),
          ),
        ],
      ),
    ); 

Output:

enter image description here

1 Comment

Is there any way to load dynamic data into each list items? @jitsm555
2

I use this property to achieve the desired result

      shrinkWrap: true,
      physics: ScrollPhysics(),

Comments

0
        Scaffold(
  backgroundColor: Colors.white,
  appBar: new AppBar(
    title: new Text('Search'),
  ),
  body: new GestureDetector(
    behavior: HitTestBehavior.opaque,
    onPanDown: (detail) {
      print(detail);
      FocusScope.of(context).requestFocus(new FocusNode());
    },
    child: new ListView(
      children: <Widget>[
        new SizedBox(height: 20.0),
        new Container(
          height: 60.0,
          color: Colors.blue,
          child: new Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Icon(Icons.hourglass_empty,
                  color: Colors.white, size: 30.0),
              new Padding(padding: const EdgeInsets.only(right: 5.0)),
              new Text('TOP5',
                  style:
                      new TextStyle(color: Colors.white, fontSize: 23.0)),
            ],
          ),
        ),
        new SizedBox(height: 20.0),
        new ListView.builder(
          shrinkWrap: true,
          itemCount: 5,
          physics: NeverScrollableScrollPhysics(),
          itemBuilder: (context, index) {
            return new Column(
              children: <Widget>[
                new Container(
                  height: 50.0,
                  color: Colors.green,
                  child: new Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      new Icon(Icons.format_list_numbered,
                          color: Colors.white),
                      new Padding(
                          padding: const EdgeInsets.only(right: 5.0)),
                      new Text(arr[index],
                          style: new TextStyle(
                              fontSize: 20.0, color: Colors.white)),
                    ],
                  ),
                ),
                new Container(
                  height: 150.0,
                  child: new ListView.builder(
                    shrinkWrap: true,
                    scrollDirection: Axis.horizontal,
                    itemCount: 10,
                    itemBuilder: (context, index) {
                      return new GestureDetector(
                        child: new Card(
                          elevation: 5.0,
                          child: new Container(
                            height: MediaQuery.of(context).size.width / 3,
                            width: MediaQuery.of(context).size.width / 3,
                            alignment: Alignment.center,
                            child: new Text('Item $index'),
                          ),
                        ),
                        onTap: () {
                          print(123);
                        },
                      );
                    },
                  ),
                ),
                new SizedBox(height: 20.0),
              ],
            );
          },
        ),
      ],
    ),
  ),
);

1 Comment

Try this it's work perfect. I just only added physics: NeverScrollableScrollPhysics(), & it's work. Here, video link. drive.google.com/file/d/1Wxbsm3c2_IJCeDqoN6EQGRYLnht0GqrJ/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.