I'm building a Flutter screen that has a transparent AppBar in the parent Scaffold and a child screen (LobbyScreen) with its own CustomScrollView. I want to pin a SliverPersistentHeader below the transparent AppBar. However, when I set extendBodyBehindAppBar: true, my pinned header scrolls behind the AppBar.
class _HomeScreenState extends State<HomeScreen> {
final ScrollController _homeScrollController = ScrollController();
late int _selectedIndex = 0;
late final List<Widget> _homeWidgets = <Widget>[
LobbyScreen(scrollController: _homeScrollController),
// ... another screen here ...
];
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true, // needed for transparency
appBar: CoruscantHomeTopBarWidget(
leading: Image.asset(AppImages.topBarLogo),
trailingBarWidget: /* some trailing widget */,
),
body: _homeWidgets.elementAt(_selectedIndex),
floatingActionButton: /* ... */,
bottomNavigationBar: /* ... */,
);
}
}
Inside LobbyScreen, I use a CustomScrollView that contains a pinned sliver (CustomStickyTabBarWidget), which internally uses a SliverPersistentHeader:
class LobbyScreen extends StatelessWidget {
const LobbyScreen({
required this.scrollController,
super.key,
});
final ScrollController scrollController;
@override
Widget build(BuildContext context) {
return CustomScrollView(
controller: scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: _MatchCardWidget(
// ...
),
),
),
const SliverToBoxAdapter(
child: CoruscantGap(16),
),
SliverToBoxAdapter(
child: HorizontalMatchCardsWidget(
// ...
),
),
const SliverToBoxAdapter(
child: CoruscantGap(16),
),
// More SliverToBoxAdapter ...
CustomStickyTabBarWidget(
initialIndex: 0,
tabs: tabs,
tabSlivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 24),
sliver: SliverList.builder(
itemCount: mockLobbyMatch.length,
itemBuilder: (BuildContext context, int index) {
return /* ... cards ... */;
},
),
),
// More slivers for other tabs
],
),
const SliverToBoxAdapter(
child: CoruscantGap(16),
),
],
);
}
}
The CustomStickyTabBarWidget uses:
@override
Widget build(BuildContext context) {
return SliverMainAxisGroup(
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: _TabsViewWithFilters(
currentIndex: _currentIndex,
// ...
),
),
// Show different slivers per tab
widget.tabSlivers[_tabController.index],
],
);
}
The Problem: Because extendBodyBehindAppBar: true is set on the Scaffold, the pinned header in LobbyScreen is pinned at the top of its scroll context — which visually places it under the transparent app bar. I’ve tried: Adding a SliverToBoxAdapter(child: SizedBox(height: kToolbarHeight)) at the top of the CustomScrollView in LobbyScreen. It offset the pinned header, but it also disrupted the rest of my layout (extra gap where I don’t want it). Changing the AppBar to a SliverAppBar inside one CustomScrollView, but that conflicts with my existing design and usage of the parent Scaffold.
Question how can I make the tabbarWidget stick under the app bar while keeping my UI same i.e not losing transparency