Reputation: 17160
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 a ListView.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/root ListView
in order to fade my navigation bar in and out. This works as expected.
However, adding the ScrollController
to the ListView
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 nestedt ListView.builder
, the root ListView
scrolls/bounces, but then I can no longer adjust the UI based on the offset as it's on the wrong ListView
.
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.
Even if I remove the stack and nested ListView
, a simple, singlular ListView
with the ScrollController
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,
),
),
),
],
);
}
Upvotes: 2
Views: 5041
Reputation: 17160
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
Upvotes: 3