capsule_nav_bar 1.2.0
capsule_nav_bar: ^1.2.0 copied to clipboard
A bottom navigation bar that floats over the content as a rounded capsule, its selection marked by a pill sliding between destinations.
import 'package:capsule_nav_bar/capsule_nav_bar.dart';
import 'package:material_ui/material_ui.dart';
import 'demo_content.dart';
import 'demo_destinations.dart';
import 'demo_theme.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
ThemeMode _mode = ThemeMode.light;
bool _rtl = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'capsule_nav_bar',
debugShowCheckedModeBanner: false,
theme: buildDemoTheme(Brightness.light),
darkTheme: buildDemoTheme(Brightness.dark),
themeMode: _mode,
home: Directionality(
textDirection: _rtl ? TextDirection.rtl : TextDirection.ltr,
child: ExamplePage(
isDark: _mode == ThemeMode.dark,
onToggleBrightness: () => setState(
() => _mode = _mode == ThemeMode.dark
? ThemeMode.light
: ThemeMode.dark,
),
onToggleDirection: () => setState(() => _rtl = !_rtl),
),
),
);
}
}
class ExamplePage extends StatefulWidget {
const ExamplePage({
super.key,
required this.isDark,
required this.onToggleBrightness,
required this.onToggleDirection,
});
final bool isDark;
final VoidCallback onToggleBrightness;
final VoidCallback onToggleDirection;
@override
State<ExamplePage> createState() => _ExamplePageState();
}
class _ExamplePageState extends State<ExamplePage> {
int _index = 0;
bool _glass = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(demoDestinations[_index].label),
actions: [
IconButton(
tooltip: 'Toggle brightness',
icon: Icon(widget.isDark ? Icons.light_mode : Icons.dark_mode),
onPressed: widget.onToggleBrightness,
),
IconButton(
tooltip: 'Toggle text direction',
icon: const Icon(Icons.swap_horiz),
onPressed: widget.onToggleDirection,
),
IconButton(
tooltip: _glass ? 'Glass on' : 'Glass off',
icon: Icon(_glass ? Icons.blur_on : Icons.blur_off),
onPressed: () => setState(() => _glass = !_glass),
),
],
),
// The bar overlaps the content, so it goes in a Stack over it rather
// than in Scaffold.bottomNavigationBar — that is what the scrim behind
// it is for.
body: Stack(
children: [
DemoContent(index: _index),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: CapsuleNavBar(
destinations: demoDestinations,
activeIndex: _index,
onDestinationSelected: (i) => setState(() => _index = i),
glass: _glass,
// The demo theme's bar is nearly opaque, which would hide the
// frost — a glass bar has to let what is behind it through.
barColor: _glass
? Theme.of(
context,
).colorScheme.surfaceContainerLow.withValues(alpha: 0.55)
: null,
// The scrim would fill in exactly what the glass is there to
// show, so it stands down while the frost is on.
showScrim: !_glass,
semanticLabel: 'Main navigation',
),
),
],
),
);
}
}