7

I need to build a page with lists of objects that are grouped in a single line. This needs to be scrolled both vertically (to show more groups) and horizontally (to show groups children). The vertical and horizontal scroll needs to move the items altogether. Something like this: https://gph.is/g/46gjW0q

I'm doing this with this code:

Widget _buildGroups() {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Container(
        width: 2000,
        child: ListView.builder(
          scrollDirection: Axis.vertical,
          itemCount: boardData.length,
          itemBuilder: (context, index) {
            return Row(children: _buildSingleGroup(index));
          },
        ),
      ),
    );
}

List<Widget> _buildSingleGroup(int groupIndex) {
    return List.generate(...);
}

I need this to be horizontally dynamic but here, as you can see, I need to set a width cause otherwise an error occurs:

══════════════════ Exception caught by rendering library ═════════════════════
The following assertion was thrown during performResize()
Vertical viewport was given unbounded width.

Viewports expand in the cross axis to fill their container and constrain their 
children to match their extent in the cross axis. In this case, a vertical 
viewport was given an unlimited amount of horizontal space in which to expand.

I tried to set "shrinkWrap: true" in the ListView but the result gives another error:

Failed assertion: line 1629 pos 16: 'constraints.hasBoundedWidth': is not true.

So how do you do this with a dynamical ListView width?

Davide Bicego
  • 562
  • 2
  • 6
  • 24
  • 1
    is there a reason you're not using a nested ListView? Listview with vertical scroll and inside of that another listview with horizontal scroll – Gino Oct 21 '19 at 10:50
  • Hi @Gino, If I would do like you said every row would scroll on his own, it's not the behave i want – Davide Bicego Oct 21 '19 at 11:14
  • I should also mention that I need to use ListView widgets so that I can implement a loadMoreRows function to load more data and, if possible, to not make Flutter reload all the widgets in the page. I've already achieved the wanted result using SingleChildScrollViews and Lists but that doesn't allow me to handle the loadMoreRows thing in an efficient way – Davide Bicego Oct 21 '19 at 11:20

2 Answers2

2

The error happens because when ListView tries to get height from its parent to fill the entire height, the parent returns infinity height because SingleChildScrollView doesn't have fixed container height value. To fix that issue you need to limit the height value. For example, I used SizedBox to specify height for ListView.

The following code works for me.

SingleChildScrollView(
  child: Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      SizedBox(
        height: 120, // <-- you should put some value here
        child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: items.length,
          itemBuilder: (context, index) {
            return Text('it works');
          },
        ),
      ),
    ],
  ),
);
TheMisir
  • 4,083
  • 1
  • 27
  • 37
-2

Please can you explain your guess about the objects size?

I have a solution, but in my solution , flutter will build all objects (In both axes) for first frame. And build again any setState in the three. So its not good solition.

Last scroll offset horizontally enter image description here and enter image description here But I'll explain anyway.

///
class BothAxisScroll extends StatefulWidget {
  @override
  _BothAxisScrollState createState() => _BothAxisScrollState();
}

class _BothAxisScrollState extends State<BothAxisScroll> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        padding: const EdgeInsets.all(30),
        child: Container(
          alignment: Alignment.topLeft,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: _build(),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

List<Widget> _build() {
  return List.generate(
      20,
      (index) => Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.start,
            children: _buildSingleGroup(index),
          ));
}

List<Widget> _buildSingleGroup(int _index) {
  return List.generate(
    Random().nextInt(20),
    (index) {
      print('BUILD: $_index');
      return Container(
          padding: const EdgeInsets.all(15), child: Text("$_index-$index"));
    },
  );
}

and result in first frame :

enter image description here

Mehmet Yaz
  • 195
  • 3