collapsible_side_menu 1.0.2
collapsible_side_menu: ^1.0.2 copied to clipboard
A Flutter customizable collapsible side menu with sub-menus and text direction features.
collapsible_side_menu #
collapsible_side_menu is a highly customizable Flutter package for building a collapsible side menu, with text direction (LTR & RTL) and sub-menu features.
| Mobile | Desktop | Web |
|---|---|---|
| [Mobile] | [Desktop] | [Web] |
Full mobile and desktop demo videos.
Table of contents #
Features #
- set menu animation duration
- set menu behaviour
- set menu text direction
- set toggle button and it's look
- add tiles and and their sub-tiles
- customize menu, tile and sub-tile look
Usage #
Installation #
Add to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
# add this line
collapsible_side_menu: ^latest_version
or run
flutter pub add collapsible_side_menu
Import package #
Add the following line to your code
import 'package:collapsible_side_menu/collapsible_side_menu.dart';
Basic usage example #
static const TextDirection menutextDirection = TextDirection.rtl;
CollapsibleSideMenu(
defaultIndex: 3,
defaultBehaviour: .open,
menuStyle: SideMenuStyle(textDirection: menutextDirection),
toggleButtonStyle: const ToggleButtonStyle(topPosition: 55, iconSize: 16),
header: (_, isOpen) {
return Column(
crossAxisAlignment: .start,
children: [
Row(
spacing: 10,
mainAxisSize: .min,
children: [
const Flexible(child: CircleAvatar(radius: 22, child: FlutterLogo())),
if (isOpen)
const Flexible(
flex: 2,
child: Column(
crossAxisAlignment: .start,
children: [
Text(
'Joanna Doe',
overflow: .ellipsis,
style: TextStyle(fontWeight: .w500, fontSize: 14.5),
),
Text(
'joanna.doe.404@flutter.dev',
overflow: .ellipsis,
style: TextStyle(fontSize: 12, fontWeight: .w300),
),
],
),
),
],
),
const Divider(thickness: .5),
],
);
},
footer: (_, isOpen) {
return Column(
mainAxisAlignment: .end,
crossAxisAlignment: .start,
children: [
const Divider(thickness: .5),
Text('v1.0.1+1', style: TextStyle(fontSize: isOpen ? 12 : 10)),
],
);
},
items: [
TileData(
title: 'User management',
leading: const Icon(Icons.person_outline, size: 18),
selectedLeading: const Icon(Icons.person, size: 18),
subTiles: [
SubTileData(title: 'Customers'),
SubTileData(
title: 'Employees',
subTiles: [
SubTileData(title: 'Drivers'),
SubTileData(title: 'HR'),
SubTileData(title: 'Accountants'),
SubTileData(title: 'Marketing'),
],
),
SubTileData(
title: 'Admins',
subTiles: [
SubTileData(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Sudo')));
},
title: 'Sudo',
leading: const Icon(Icons.shield, size: 18),
),
SubTileData(title: 'Super-admins'),
SubTileData(title: 'Admins'),
],
),
SubTileData(title: 'Salaries', trailing: const Icon(Icons.attach_money, size: 18)),
],
),
//
const DividerData(),
const TitleData(title: 'OTHERS'),
TileData(onTap: () {}, title: 'Vehicle', leading: const Icon(Icons.car_rental, size: 18)),
TileData(
onTap: () {},
title: 'Conversations',
leading: const Icon(Icons.chat_bubble_outline, size: 18),
selectedLeading: const Icon(Icons.chat_bubble, size: 18),
badgeBuilder: (tile) => Badge.count(count: 100, maxCount: 9, offset: Offset(menutextDirection == .rtl ? 2 : -2, -4), child: tile),
),
TileData(title: 'Labels', leading: const Icon(Icons.label_outline), selectedLeading: const Icon(Icons.label)),
TileData(
onTap: () {
showAdaptiveAboutDialog(context: context);
},
title: 'About',
leading: const Icon(Icons.info_outline, size: 18),
selectedLeading: const Icon(Icons.info, size: 18),
),
TileData(
onTap: () {
showLicensePage(context: context);
},
title: 'Licenses',
leading: const Icon(Icons.copyright_outlined, size: 18),
selectedLeading: const Icon(Icons.copyright, size: 18),
),
],
onIndexChanged: (index) {
debugPrint('current index: $index');
},
),
Elements, types, usage and description #
| Element | Type | Usage | Description |
|---|---|---|---|
| SideMenu | Widget | Menu widget | The side menu widget |
| SideMenuStyle | Class | Style | Menu container style |
| MenuTileStyle | Class | Style | Menu tile style |
| SubMenuTileStyle | Class | Style | Menu sub-tile style |
| ToggleButtonStyle | Class | Style | Toggle button style (to open/close the menu) |
| SideMenuController | Class | Controller | Menu controller |
| TitleData | Class | Data | Add a simple text with custom style (with no background or tap callback) to items |
| DividerData | Class | Data | Add a custom divider widget to items |
| TileData | Class | Data | Add a tile to items |
| SubTileData | Class | Data | Add a sub-tile to tile (TileData) |
| TileBadgeBuilder | Class | Builder | Data to build a badge on a tile |
| CustomChildPosition | Enum | Enum | Position of the custom child related to items (above or below) |
| AutoOpenFrom | Enum | Enum | Set from what screen width the menu should adapt when defaultBehaviour is set to auto |
Class, parameters, types and defaults #
| Class | Parameters | Types | Defaults |
|---|---|---|---|
| SideMenu | header | MenuHeaderBuilder? | null |
| footer | MenuHeaderBuilder? | null | |
| customMenuChild | CustomMenuChild? | null | |
| items | List<SideMenuItem> | const [] | |
| spacerAfterItems | Spacer? | null | |
| onIndexChanged | ValueChanged<int>? | null | |
| controller | SideMenuController? | null | |
| defaultBehaviour | MenuBehaviour | MenuBehaviour.auto | |
| autoFrom | AutoOpenFrom | AutoOpenFrom.tablet | |
| minWidth | double | MenuConstants.minWidth | |
| maxWidth | double | MenuConstants.maxWidth | |
| hasToggleButton | bool | true | |
| toggleButtonStyle | ToggleButtonStyle? | null | |
| duration | Duration | MenuConstants.duration | |
| animationCurve | Curve | Curves.linear | |
| menuStyle | SideMenuStyle? | null | |
| defaultIndex | int? | null | |
| SideMenuStyle | backgroundColor | Color? | colorScheme.primary |
| boxShadow | BoxShadow? | null | |
| textDirection | TextDirection? | Directionality.of(context) | |
| borderRadius | BorderRadiusGeometry | MenuConstants.borderRadius | |
| padding | EdgeInsetsGeometry | MenuConstants.menuInnerPadding | |
| margin | EdgeInsetsGeometry | MenuConstants.outerPadding | |
| defaultTileStyle | MenuTileStyle | null | |
| MenuTileStyle | titleStyle | TextStyle? | TextStyle(fontSize: 13.7) |
| selectedTitleStyle | TextStyle? | TextStyle(fontSize: 13.7, fontWeight: .w500) | |
| color | Color? | Set depending on menu background color luminance (if not null), else set to colorScheme.onPrimary | |
| selectedColor | Color? | It's set to Colors.black or Colors.white depending on colorScheme.inversePrimary luminance | |
| hoverColor | Color? | colorScheme.onSecondaryContainer | |
| backgroundColor | Color | MenuConstants.transparent | |
| selectedBackgroundColor | Color? | colorScheme.inversePrimary | |
| borderRadius | BorderRadius | MenuConstants.borderRadius | |
| decoration | Decoration? | BoxDecoration(borderRadius: MenuConstants.borderRadius) | |
| selectedDecoration | Decoration? | BoxDecoration(color: colorScheme.inversePrimary, borderRadius: MenuConstants.borderRadius) | |
| selectedIndicator | Decoration? | BoxDecoration(borderRadius: MenuConstants.borderRadius) with the right color | |
| padding | EdgeInsetsGeometry | EdgeInsets.zero | |
| margin | EdgeInsetsGeometry | MenuConstants.tileMargin | |
| subTileStyle | SubMenuTileStyle? | refer to SubMenuTileStyle section | |
| tileHeight | double | MenuConstants.tileHeight | |
| subTileHeight | double | MenuConstants.subTileHeight | |
| horizontalSpacing | double | MenuConstants.horizontalSpacing | |
| SubMenuTileStyle | titleStyle | TextStyle? | TextStyle(fontSize: 12.3) |
| selectedTitleStyle | TextStyle? | TextStyle(fontSize: 12.3, fontWeight: .w500) | |
| selectedColor | Color? | colorScheme.onSecondaryContainer | |
| backgroundColor | Color | MenuConstants.transparent | |
| color | Color? | Set depending on background color luminance (if not null), else set to colorScheme.onSecondary | |
| hoverColor | Color? | colorScheme.onSecondaryContainer | |
| selectedBackgroundColor | Color? | null | |
| borderRadius | BorderRadius | MenuConstants.borderRadius | |
| decoration | Decoration? | BoxDecoration(borderRadius: MenuConstants.borderRadius) | |
| selectedDecoration | Decoration? | BoxDecoration(color: colorScheme.secondaryContainer, borderRadius: MenuConstants.borderRadius) | |
| padding | EdgeInsetsGeometry | EdgeInsets.zero | |
| margin | EdgeInsetsGeometry | MenuConstants.tileMargin | |
| horizontalSpacing | double | MenuConstants.horizontalSpacing | |
| defaultSubTilesStyle | SubMenuTileStyle? | null | |
| tileHeight | double | MenuConstants.subTileHeight | |
| ToggleButtonStyle | iconColor | Color? | null |
| topPosition | double | 20.0 | |
| opacity | double | 0.7 | |
| iconSize | double | 20.0 | |
| icon | IconData? | null | |
| backgroundColor | Color? | ColorScheme.of(context).inversePrimary |
⚠️Warning #
This package was only tested on Android, Linux and web so feedback is needed for other platforms.