Nested ListView with ScrollController Not Scrolling
Resolved by wrapping the parent ListView
in a PrimaryScrollController
then setting primary = true
on the ListView
.
This lets PrimaryScrollController
manage the controller, but the ListView
maintains typical scrolling behaviour as it no longer manages the ScrollController
.
See Flutter docs: https://api.flutter.dev/flutter/widgets/ScrollView/primary.html
Josh Kahane
Updated on December 01, 2022Comments
-
Josh Kahane over 1 year
I am building a widget with a custom navigation bar which includes a
Stack
with the main body and the navigation bar.@override Widget build(BuildContext context) { return Stack( children: [ _buildBody(), _buildNavigationBar(), ], ); }
The body consists of a
ListView
with a header and aListView.builder
nested below that for the contents.Widget _buildBody() { return ListView( padding: EdgeInsets.only(top: 44.0 + MediaQuery.of(context).padding.top), controller: _scrollController, children: [ Opacity( opacity: 1.0 - _navigationBarOpacity, child: Padding( padding: const EdgeInsets.only(bottom: 15.0), child: _buildHeaderTitle( title: widget.title, fontSize: _largeFontSize, fontWeight: _largeFontWeight, color: widget.color, ), ), ), ListView.builder( padding: EdgeInsets.zero, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: widget.itemCount, itemBuilder: (context, index) { return widget.itemBuilder(context, index); }, ), ], ); }
I'm using a
ScrollController
on the primary/rootListView
in order to fade my navigation bar in and out. This works as expected.However, adding the
ScrollController
to theListView
stops any scrolling/bouncing interaction. How can I fix this?ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); _scrollController.addListener(() { setState(() { double min = 0.0; double max = 25.0; _navigationBarOpacity = (_scrollController.offset - min) / (max - min); if (_navigationBarOpacity < 0) _navigationBarOpacity = 0; if (_navigationBarOpacity > 1) _navigationBarOpacity = 1; }); }); }
Interestingly, if I move the
ScrollController
to the nestedtListView.builder
, the rootListView
scrolls/bounces, but then I can no longer adjust the UI based on the offset as it's on the wrongListView
.Another point of interest, the root
ListView
scrolls normally if it's children exceed it's height. However, there are cases where it won't have that and I'd expect it just to bounce on pulling.
Update
Even if I remove the stack and nested
ListView
, a simple, singlularListView
with theScrollController
won't scroll on drag, without it, it will. This is the root issue that needs resolving.@override Widget build(BuildContext context) { return ListView( padding: EdgeInsets.only(top: 44.0 + MediaQuery.of(context).padding.top), controller: _scrollController, children: [ Opacity( opacity: 1.0 - _navigationBarOpacity, child: Padding( padding: const EdgeInsets.only(bottom: 15.0), child: _buildHeaderTitle( title: widget.title, fontSize: _largeFontSize, fontWeight: _largeFontWeight, color: widget.color, ), ), ), ], ); }
-
Pavel over 3 yearsConsider using
CustomScrollView
withSliverAppBar
andSliverList
(SliverChildBuilderDelegate
) -
Josh Kahane over 3 yearsThis doesn't create the effect I desire, nor does it provide me the flexibility to customise it further to me needs going forward. Hence the need to resolve, or at least understand why I am facing the
ScrollController
issue.
-