Search code examples
flutterdartflutter-layout

ListView Builder vs SingleChildScrollView + Row combo


I want to make a responsive UI in my app. In my home page, I have ScrollView->Column->childrens structure.

When I want to use horizontal Listview.builder in my column, it throws me error because height is unbounded. I fix it with wrapping my listview builder with container and I give this container a height value. But I dont want to give this height hardcoded,

I want to make my container height to its own child's height. I searched it and found a solution like ScrollView->Row->list.generate instead of ListView.Builder. But is it okay to make it like this? Does it cause performance problems or is it a bad practice?

My list isn't big. It has max 20 elements

For example this throwing error:

@override   Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: SingleChildScrollView(
          child: Column(
        children: [
          ListView.builder(
            itemCount: 5,
            physics: NeverScrollableScrollPhysics(),
            scrollDirection: Axis.horizontal,
            shrinkWrap: true,
            itemBuilder: (context, index) {
              return Container(
                width: 200,
                height: 200,
              );
            },
          )
        ],
      )),
    );   }

But this does not throw an error

@override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        child: Column(
      children: [
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: List.generate(
                5,
                (index) => Container(
                      width: 200,
                      height: 200,
                      color: Colors.red,
                    )),
          ),
        ),
      ],
    ));
  }

Solution

  • To clarify for everyone:

    ListViews generate their children "lazily" - meaning they won't be drawn until they have been shown on screen. This means, of course, that they do not know the height of their items.

    For example, if the ListViews children have heights similar to this list:

    ooooOooo

    But only this part was shown on the screen:

    oooo | Oooo

    And the ListView set it's height to fit "o" then it wouldn't be able to fit "O" when it eventually came on screen.


    On the other hand, Rows do draw all of their children on spawn, meaning that, while they do know the size for all their widgets, they can become very slow quickly.

    I would not suggest using images inside rows with 2-digit+ children, as they can be laggy not only on their initial draw, but also while the user does other things in the page containing said row - things such as scrolling up/down the page.

    While testing I found that a row with just 30 children of the same stack (a small AssetImage on top of an IconImage) would lag the entire page when just scrolling up/down - not even scrolling along the row itself.


    My recommended solution for you Ahmet, even though you don't want to hard-code your ListView's height, is to settle and set your ListView's height using:

    MediaQuery.of(context).size.height * (percentage of screen's height you'd like for the ListView to take).