Reputation: 151
I'm trying to use a NestedScrollView
for scrollable tabs within a DraggableScrollableSheet
and need to pass the sheet's controller to the NestedScrollView
's scrollable body, however doing so is not supported by NestedScrollView
which requires that inner scrollables implicitly use the context's PrimaryScrollController
.
The resultant behaviour is that I am seeing:
I've tried a multiple combinations of NestedScrollView
, CustomScrollView
, and TabView
, tried adding the controller to all, some, none of the scrollables. No luck. I have even tried listening to Notification
events from either attached scrollable and update the other one with those events to try to keep them in sync. Nada.
Would appreciate any and all help on this, I've been tearing my hair out for a while now. Thank you!
Here's the code for main.dart
in the video above:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: DraggableScrollableSheet(
initialChildSize: 0.6,
maxChildSize: 0.9,
minChildSize: 0.6,
builder: (context, scrollController) => DefaultTabController(
length: 2,
child: _buildNestedScrollView(scrollController),
),
),
);
}
NestedScrollView _buildNestedScrollView(ScrollController scrollController) {
return NestedScrollView(
// controller: scrollController,
headerSliverBuilder: (context, innerBoxIsScrolled) {
print('innerBoxIsScrolled $innerBoxIsScrolled');
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
toolbarHeight: 0.0,
pinned: true,
primary: false,
forceElevated: innerBoxIsScrolled,
bottom: TabBar(
tabs: [
Tab(text: 'Foo'),
Tab(text: 'Bar'),
],
),
),
),
];
},
body: TabBarView(
children: [
ListView.builder(
controller: scrollController,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (context, index) => Container(
color: Colors.primaries[index % 10],
height: 150.0,
),
),
ListView.builder(
// controller: scrollController,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (context, index) => Container(
color: Colors.primaries[index % 10],
height: 25.0,
),
),
],
),
);
}
}
Relevant links:
https://api.flutter.dev/flutter/widgets/ScrollableWidgetBuilder.html
https://api.flutter.dev/flutter/widgets/NestedScrollView/body.html
Potentially relevant Flutter issue.
Upvotes: 13
Views: 1543
Reputation: 1304
smart solution
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SizedBox.expand(
child: DraggableScrollableSheet(
initialChildSize: 0.6,
maxChildSize: 0.9,
minChildSize: 0.6,
builder: (context, scrollController) => DefaultTabController(
length: 2,
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleChildScrollView(
physics: ClampingScrollPhysics(),
controller: scrollController,
child: Container(
color: Colors.white,
child: const TabBar(tabs: [
Tab(text: 'Foo'),
Tab(text: 'Bar'),
]),
),
),
Expanded(
child: TabBarView(
children: [
ListView.builder(
controller: scrollController,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (context, index) => Container(
color: Colors.primaries[index % 10],
height: 150.0,
),
),
ListView.builder(
// controller: scrollController,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (context, index) => Container(
color: Colors.primaries[index % 10],
height: 25.0,
),
),
],
),
)
],
)),
),
),
),
);
}
}
Upvotes: 3