collapsible_tab_bar
A Material tab bar that shrinks smoothly on scroll and snaps back on tap,
with pluggable tab styles. Drive the collapse from any scroll position (a
ScrollController/ScrollNotification, a SliverPersistentHeader, etc.) by
feeding a 0.0–1.0 progress value into CollapseScope.
Features
ButtonsTabBar— aPreferredSizeWidgettab bar with per-tab filled or transparent card backgrounds, a selection underline, and a height that interpolates down to 31px as collapse progress goes from 0 to 1.- Four tab content styles:
ButtonsTab— image icon + label (shrinks/fades icon as it collapses).TextButtonsTab— text only, with optional badge overlay.IconButtonsTab—IconDataicon only.IconLabelTab—IconDataicon + label (same collapse behavior asButtonsTab, no image assets required).
CollapseScope— anInheritedWidgetthat publishescollapseProgress(0.0–1.0) andisCollapsedto the tab bar and its tabs.
Usage
Drive CollapseScope's progress from your own scroll listener, then pass it
down to a ButtonsTabBar:
import 'package:collapsible_tab_bar/collapsible_tab_bar.dart';
class MyScreen extends StatefulWidget {
const MyScreen({super.key});
@override
State<MyScreen> createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> with TickerProviderStateMixin {
late final TabController _tabController =
TabController(length: 2, vsync: this);
late final AnimationController _collapseController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
bool _onScroll(ScrollNotification notification) {
if (notification.metrics.axis != Axis.vertical) return false;
if (notification is ScrollUpdateNotification) {
final double progress =
(notification.metrics.pixels / 60.0).clamp(0.0, 1.0);
_collapseController.value = progress;
}
return false;
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _collapseController,
builder: (context, _) {
return CollapseScope(
isCollapsed: _collapseController.value >= 1.0,
collapseProgress: _collapseController.value,
child: Scaffold(
appBar: ButtonsTabBar(
controller: _tabController,
tabs: const [
IconLabelTab(icon: Icons.home_rounded, label: 'Home', index: 0),
IconLabelTab(icon: Icons.person_rounded, label: 'Profile', index: 1),
],
),
body: NotificationListener<ScrollNotification>(
onNotification: _onScroll,
child: TabBarView(
controller: _tabController,
children: const [Center(child: Text('Home')), Center(child: Text('Profile'))],
),
),
),
);
},
);
}
}
See example/ for a complete, runnable demo (4-tab card-style bar matching
a real app's collapsing header, with corner radius animating from fully
rounded to top-only rounded as it collapses).
Notes
ButtonsTab(the image-asset variant) readsSizeConfig.widthMultiplier/heightMultiplier, which this package exports. If you useButtonsTab, initialize sizing first (e.g. viaflutter_screenutil'sScreenUtilInitand callingSizeConfig.init()in itsbuilder) before the icon is built.TextButtonsTab,IconButtonsTab, andIconLabelTabdo not require this.
Libraries
- collapsible_tab_bar
- A scroll-collapsing Material tab bar for Flutter.