# Sticky Tab Bar
This Flutter code demonstrates a sticky tab bar with a list that scrolls independently. It uses a NestedScrollView to create a layout where the tab bar remains pinned at the top while the content below it scrolls.

# Requirements
lib/theme/colors.dart
# Notes
To modify the appearance of tabs, edit TabBarTheme in files
lib/theme/light_theme/tab_bar_theme.dartandlib/theme/dark_theme/tab_bar_theme.dart
To change the alignment and scrollability of the tabs, use the
tabAlignmentandisScrollableproperties inside TabBar widget.
# Code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../../theme/colors.dart';
class StickyTabScreen extends StatefulWidget {
const StickyTabScreen({super.key});
State<StickyTabScreen> createState() => _StickyTabScreenState();
}
class _StickyTabScreenState extends State<StickyTabScreen> with SingleTickerProviderStateMixin {
/// Variables
late TabController _tabController;
final List<String> _tabs = ["Workout", "Playlist", "Recipe", "Guide"];
/// Init
void initState() {
_tabController = TabController(length: _tabs.length, vsync: this);
super.initState();
}
/// Dispose
void dispose() {
_tabController.dispose();
super.dispose();
}
/// Widget
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark),
child: Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0,
title: const Text("StickyTabScreen"),
),
drawer: const Drawer(),
body: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
/// Top Area
SliverToBoxAdapter(
child: Container(
height: 200,
width: double.infinity,
alignment: Alignment.center,
child: const Text("Top Header Area"),
),
),
/// Tabs
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
TabBar(
controller: _tabController,
dividerColor: Colors.transparent,
tabAlignment: TabAlignment.center,
isScrollable: true,
tabs: _tabs.map((t) => Tab(text: t)).toList(),
),
),
),
],
/// Body
body: TabBarView(
controller: _tabController,
children: [
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 320,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 30,
color: index % 2 == 0
? Colors.blue[100]
: Colors.green[100],
child: Center(child: Text('$index')),
);
}),
Container(),
Container(),
Container(),
],
),
),
),
),
);
}
}
/// App bar delegate
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
double get minExtent => _tabBar.preferredSize.height;
double get maxExtent => _tabBar.preferredSize.height;
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Theme.of(context).brightness == Brightness.dark
? darkPrimaryColor
: primaryColor,
child: _tabBar,
);
}
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}