'Flutter: Get ListView size to create dynamic item sizes

I'm trying to create a ListView in Flutter where the total sum of its items' width is the width of the ListView itself.

In other words: I have 24 items, and I want each one to have an extent of [ListView.width]/24. However, I cannot seem to get the width of the list view inside of its builder.

I tried using context.size.width:

 itemBuilder: (context, i) {
 return Container(
            width: context.size.width,
 //And so on....

but I get the following error:

Cannot get size during build.

I also tried using Extended at each of the item's root, but it predictably didn't work.

Is there any way to obtain the width of the item's parent (the list view) and use it to calculate its extent dynamically?

Thanks.



Solution 1:[1]

If you're trying to get the ListView to display some items horizontally across the widget, put the children inside a Row and wrap each with an Expanded:

ListView.builder(
  itemCount: 1,
  itemBuilder: (_, i) => Row(
    children: [
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
      Expanded(child: Container(height: 50, color: Colors.red)),
      Expanded(child: Container(height: 50, color: Colors.blue)),
    ],
  ),
),

If you're trying to do this with a ListView in a horizontal orientation, then I would recommend to not use a ListView at all. Just use the Row in the first place.


EDIT: Since this answer was made, Dart has released a version that allows loops in list definitions. As such, a more proper way to do the above would be this:

ListView.builder(
  itemCount: 1,
  itemBuilder: (_, i) => Row(
    children: [
      for (int j = 0; j < 20; j++)
        Expanded(
          child: Container(
            height: 50, 
            color: j.isEven ? Colors.blue : Colors.red,
          ),
        ),
    ],
  ),
),

Solution 2:[2]

ScheduleBinding.instance.addPostFrameCallback((duration) {
    RenderBox box = _keyOfTheWidget.currentContext.getRenderObject();
    
    // For size of wiget
    Size size = box.size;

    // For position
    Offset offset = box.localToGlobal(Offset.zero);    

    setState(() => newSize = size);
});

Use this method... its postFrameCallback that happens once the widget is rendered.. you can get the size of the widget and then repaint the widget to be in your desired size.

Like here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Jerin