1

Basically, I have a Scrollable Column of Sections. Each section is an Expansion Tile, with a [ ListView ] as children attribute. (ListView uses NeverScrollPhysics, so all the children of the ListView are built at once). When I open a section (expand the tile), I want the Scrollview to scroll, such as the opened tile (only one tile can be opened at time) is located at the very top. As you can see, if there is no enough space in the bottom to make the column scrollable, I add an extra one. I call animateTo(), inside addPostFrameCallback. Before I migrated to Flutter 2, it worked perectly both in release and debug mode. But now it works fine only in debug mode, In release, the scrollview does not scroll (I've checked that scrollOffset is calulated correctly). In release mode it works only when I fastly change the collapse state from open-close-open. And also it appears to work fine for the sections that are in the very bottom. For which the extra space should be added. In other cases it just expands and no scroll is performed.

 return LayoutBuilder(builder: (context, constraints) {
              var selectedSection = sections.firstWhere(
                  (element) => element.isExpanded,
                  orElse: () => null);
              var selectedSectionIndex = sections.indexOf(selectedSection);
              scrollOffset = calculateScrollOffset(selectedSectionIndex);
              double bottomExtraSpaceHeight = calculateBottomExtraSpaceHeight(
                constraints.maxHeight,
                scrollOffset,
                selectedSection,
                sections,
              );
              bottomExtraSpace = SizedBox(height: bottomExtraSpaceHeight);
              WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
                if (_scrollController.hasClients) {
                  _scrollController.animateTo(scrollOffset,
                      duration: Duration(milliseconds: 350),
                      curve: Curves.easeIn);
                }
              });
              
              return Container(
                alignment: Alignment.topCenter,
                child: SingleChildScrollView(
                  controller: _scrollController,
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      buildFiltersRow(),
                      buildSections(sections),
                      bottomExtraSpace
                    ],
                  ),
                ),
              );
            })

If I change

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  if (_scrollController.hasClients) {
    _scrollController.animateTo(scrollOffset,
        duration: Duration(milliseconds: 350), curve: Curves.easeIn);
  }
});

to

Future.delayed(Duration(milliseconds: 200)).then((_) {
  if (_scrollController.hasClients) {
    _scrollController.animateTo(scrollOffset,
        duration: Duration(milliseconds: 350),
        curve: Curves.easeIn);
  }
});

it start to work fine, but it does not seem like a good solution. Any thoughts about what I am doing wrong and how it can be fixed in a proper way would be appreciated. Thanks!

nvoigt
  • 75,013
  • 26
  • 93
  • 142
estatico
  • 93
  • 8
  • tried `Scrollable.ensureVisible`? – pskink Apr 09 '21 at 08:43
  • You mean to add the GlobalKey to every section, and then instead of ```_scrollController.animateTo(...)```, use ```Scrollable.ensureVisible()```? If yes, so no, I have not tried it, because as far as I know, operations with the GlobalKey are expensive, so I am trying to avoid using them – estatico Apr 09 '21 at 08:49

0 Answers0