Goal: Add a TabView
to a CustomScrollView
.
Approach: Wrap TabView
with a SliverFillRemaining
Problem: The CustomScrollView
can be scrolled far beyond the bottom of the TabView
.
More general problem: I want a SliverAppBar.large
followed by (or containing) an image, a title, a TabBar
and a TabView
.
I have tried to create a more complex SliverAppBar.large
but have not succeeded to do so.
Therefore I did the following. Explanation: The SliverFillRemaining
has a property fillOverscroll
which can be set to false. However, this only works, if the body is not scrollable (hasScrollBody
). A TabView is scrollable, so this doesn't work. How can I modify the code, so that the white space disappears?
return DefaultTabController(
length: 2,
child: Scaffold(
body: CustomScrollView(
slivers: [
const SliverAppBar.medium(
title: Text("Title"),
),
SliverToBoxAdapter(
child: Container(
height: 100,
color: Colors.red,
),
),
SliverPersistentHeader(
pinned: true,
delegate: _TabBarDelegate(
const TabBar(
tabs: [
Tab(text: 'Tab1'),
Tab(text: 'Tab2'),
],
),
),
),
SliverFillRemaining(
hasScrollBody: true,
// for this to work, the child should not be scrollable
fillOverscroll: false,
child: TabBarView(
children: [someListView1, someListView2],
),
),
),
],
)));
Goal: Add a TabView
to a CustomScrollView
.
Approach: Wrap TabView
with a SliverFillRemaining
Problem: The CustomScrollView
can be scrolled far beyond the bottom of the TabView
.
More general problem: I want a SliverAppBar.large
followed by (or containing) an image, a title, a TabBar
and a TabView
.
I have tried to create a more complex SliverAppBar.large
but have not succeeded to do so.
Therefore I did the following. Explanation: The SliverFillRemaining
has a property fillOverscroll
which can be set to false. However, this only works, if the body is not scrollable (hasScrollBody
). A TabView is scrollable, so this doesn't work. How can I modify the code, so that the white space disappears?
return DefaultTabController(
length: 2,
child: Scaffold(
body: CustomScrollView(
slivers: [
const SliverAppBar.medium(
title: Text("Title"),
),
SliverToBoxAdapter(
child: Container(
height: 100,
color: Colors.red,
),
),
SliverPersistentHeader(
pinned: true,
delegate: _TabBarDelegate(
const TabBar(
tabs: [
Tab(text: 'Tab1'),
Tab(text: 'Tab2'),
],
),
),
),
SliverFillRemaining(
hasScrollBody: true,
// for this to work, the child should not be scrollable
fillOverscroll: false,
child: TabBarView(
children: [someListView1, someListView2],
),
),
),
],
)));
You can try the following approach, which should help resolve the issue you're facing.
Widget HeaderWidget() {
return Scaffold(
appBar: AppBar(
title: Text('Title'),
elevation: 0.0,
),
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverToBoxAdapter(
child: Container(
color: Colors.red,
height: 100,
),
),
// SliverAppBar to make the TabBar sticky
SliverAppBar(
pinned:
true, // This ensures the TabBar stays visible when scrolling
floating: true, // Keeps the TabBar at the top of the screen
expandedHeight: 0,
// No extra space for the expanded area
bottom: TabBar(
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
],
),
),
];
},
body: TabBarView(
children: [
ListView.builder(
itemCount: 10,
itemBuilder: (context, index) => ListTile(
tileColor: Colors.green,
title: Text(
'Item $index',
style: TextStyle(color: Colors.white),
),
),
),
ListView.builder(
itemCount: 5,
itemBuilder: (context, index) => ListTile(
tileColor: Colors.red,
title: Text(
'Item $index',
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
),
);
}