curved_sidebar_navigation 0.1.1
curved_sidebar_navigation: ^0.1.1 copied to clipboard
A configurable Flutter sidebar with an animated curved cutout for the selected navigation item.
import 'package:curved_sidebar_navigation/curved_sidebar_navigation.dart';
import 'package:flutter/material.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
static const _violet = Color(0xFF5C54B7);
static const _drawerWidth = 252.0;
static const _items = [
CurvedSidebarItem(value: 0, label: 'Profile', icon: Icons.person_outline),
CurvedSidebarItem(value: 1, label: 'Projects', icon: Icons.work_outline),
CurvedSidebarItem(
value: 2,
label: 'Settings',
icon: Icons.settings_outlined,
),
];
int selected = 0;
CurvedSidebarNavigation<int> _navigation({
required bool closeOnSelected,
bool fillDrawer = false,
}) {
return CurvedSidebarNavigation<int>(
selectedValue: selected,
closeOnSelected: closeOnSelected,
onSelected: (value) => setState(() => selected = value),
backgroundColor: _violet,
panelWidth: _drawerWidth,
totalWidth: fillDrawer ? _drawerWidth : 306,
header: const _ExampleBrand(),
footer: const _ExampleFooter(),
items: _items,
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: _violet,
scaffoldBackgroundColor: const Color(0xFFF1F5FC),
useMaterial3: true,
),
home: LayoutBuilder(
builder: (context, constraints) {
final desktop = constraints.maxWidth >= 800;
if (desktop) {
return Scaffold(
body: Row(
children: [
_navigation(closeOnSelected: false),
Expanded(child: _SelectedContent(selected: selected)),
],
),
);
}
return Scaffold(
drawerScrimColor: Colors.transparent,
appBar: AppBar(title: const Text('Curved sidebar example')),
drawer: Drawer(
width: _drawerWidth,
elevation: 0,
shadowColor: Colors.transparent,
surfaceTintColor: Colors.transparent,
backgroundColor: const Color(0xFFF1F5FC),
shape: const RoundedRectangleBorder(),
child: SafeArea(
child: _navigation(closeOnSelected: true, fillDrawer: true),
),
),
body: _SelectedContent(selected: selected),
);
},
),
);
}
}
class _SelectedContent extends StatelessWidget {
const _SelectedContent({required this.selected});
final int selected;
@override
Widget build(BuildContext context) {
const labels = ['Profile', 'Projects', 'Settings'];
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.touch_app_outlined, size: 44),
const SizedBox(height: 14),
Text(
labels[selected],
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 8),
Text(
MediaQuery.sizeOf(context).width >= 800
? 'Permanent sidebar mode'
: 'Open the drawer and select another destination',
),
],
),
);
}
}
class _ExampleBrand extends StatelessWidget {
const _ExampleBrand();
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'MY APP',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w800,
letterSpacing: 1.2,
),
),
);
}
}
class _ExampleFooter extends StatelessWidget {
const _ExampleFooter();
@override
Widget build(BuildContext context) {
return Container(
width: 210,
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: .12),
borderRadius: BorderRadius.circular(18),
),
child: const Text(
'Responsive sidebar\nand drawer',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
);
}
}