responsive_scaffold_navigation 0.0.1
responsive_scaffold_navigation: ^0.0.1 copied to clipboard
A Flutter package providing an adaptive Scaffold that intelligently manages BottomNavigationBar, NavigationRail, or a persistent side navigation panel based on screen width.
Responsive Navigation Scaffold #
A Flutter package that provides an ResponsiveNavigationScaffold. This widget intelligently manages the primary navigation element (BottomNavigationBar, NavigationRail, or a persistent Drawer/Side Navigation Panel) based on screen width breakpoints, reducing boilerplate and promoting consistent responsive UI.

Features #
- 📱 Automatic Navigation Switching: Seamlessly transitions between:
BottomNavigationBarfor small screens (e.g., mobile portrait).NavigationRailfor medium screens (e.g., mobile landscape, tablet portrait).- Persistent
Draweror custom Side Navigation Panel for large screens (e.g., tablet landscape, desktop, web).
- 📌 Define Destinations Once: Specify your navigation items using
ResponsiveNavigationDestinationand let the package adapt them. - 📐 Customizable Breakpoints: Easily define screen width thresholds for
small,medium, andlargelayouts viaResponsiveBreakpoints. - 🎨 Highly Customizable:
- Provide custom builders for
BottomNavigationBar,NavigationRail, and the large screen navigation panel. - Option to extend the
NavigationRail. - Pass through most standard
Scaffoldproperties.
- Provide custom builders for
- ⚙️ AppBar Integration: Includes an option (
autoAdjustAppBarLeading) to automatically manage theAppBar's leading widget (e.g., hamburger icon for a temporary drawer). - 🧩 Reduced Boilerplate: Simplifies the implementation of common responsive navigation patterns.
Getting Started #
Prerequisites #
Ensure your Flutter environment is set up. This package is designed to work with Flutter version 3.10.0 or higher (due to features like Badge). Please check your pubspec.yaml for the exact SDK constraints.
Installation #
Add responsive_navigation_scaffold to your pubspec.yaml dependencies:
dependencies:
flutter:
sdk: flutter
responsive_navigation_scaffold: 0.0.1
Then, run flutter pub get in your terminal.
Basic Usage #
Import the package into your Dart file:
import 'package:responsive_navigation_scaffold/responsive_navigation_scaffold.dart';
Here's a simple example to get you started: #
import 'package:responsive_navigation_scaffold/responsive_navigation_scaffold.dart';
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
// 1. Define your navigation destinations
final List<ResponsiveNavigationDestination> destinations = [
ResponsiveNavigationDestination(
label: 'Home',
icon: Icons.home_outlined,
selectedIcon: Icons.home,
),
ResponsiveNavigationDestination(
label: 'Search',
icon: Icons.search_outlined,
selectedIcon: Icons.search,
),
ResponsiveNavigationDestination(
label: 'Profile',
icon: Icons.person_outline,
selectedIcon: Icons.person,
),
];
// 2. Define the views (pages) for each destination
final List<Widget> destinationViews = [
const Center(child: Text('Home Content Area')),
const Center(child: Text('Search Content Area')),
const Center(child: Text('Profile Content Area')),
];
// 3. Use ResponsiveNavigationScaffold
return ResponsiveNavigationScaffold(
selectedIndex: _selectedIndex,
destinations: destinations,
onDestinationSelected: (index) {
setState(() {
_selectedIndex = index;
});
},
appBar: AppBar(title: Text(destinations[_selectedIndex].label)), // Dynamic title
body: IndexedStack( // Use IndexedStack to preserve state of views
index: _selectedIndex,
children: destinationViews,
),
// Optional: Provide a standard drawer for settings, about page, etc.
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
const DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Text('App Menu', style: TextStyle(color: Colors.white, fontSize: 24)),
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('Settings'),
onTap: () {
Navigator.pop(context); // Close the drawer
// Navigate to Settings page or show dialog
},
),
ListTile(
leading: const Icon(Icons.info_outline),
title: const Text('About'),
onTap: () {
Navigator.pop(context); // Close the drawer
// Show About dialog
},
),
],
),
),
// Optional: Customize breakpoints (defaults are small: 600, medium: 960)
// breakpoints: const ResponsiveBreakpoints(small: 640, medium: 1024),
// Optional: Extend the NavigationRail when it's active
extendNavigationRail: true,
floatingActionButton: FloatingActionButton(
onPressed: () {
// Your FAB action
},
child: const Icon(Icons.add),
),
);
}
}
Key Components #
This section details the main classes and their important properties that form the public API of this package.
ResponsiveNavigationScaffold #
The core widget that provides the responsive layout.
Key Properties:
- selectedIndex: (required) int - The index of the currently selected navigation destination.
- destinations: (required) List
- onDestinationSelected: (required) ValueChanged
- body: (required) Widget - The main content widget to display based on the selected destination.
- appBar: AppBar? - An optional AppBar for the scaffold.
- drawer: Widget? - An optional standard Drawer that can be used for secondary navigation or app settings. It's typically opened via a hamburger icon on smaller screens.
- breakpoints: ResponsiveBreakpoints - Defines the screen width thresholds for switching navigation types. Defaults to small: 600, medium: 960.
- extendNavigationRail: bool - If true, the NavigationRail will be in its extended state (showing labels next to icons). Defaults to false.
- bottomNavigationBarBuilder: Widget Function(...)? - A builder function to provide a completely custom BottomNavigationBar.
- navigationRailBuilder: Widget Function(...)? - A builder function to provide a completely custom NavigationRail.
- largeScreenNavigationBuilder: Widget Function(...)? - A builder function to provide a custom navigation panel (e.g., persistent side bar or a custom Drawer) for large screens.
- autoAdjustAppBarLeading: bool - If true (default), the package attempts to automatically add a leading hamburger icon to the AppBar to open the drawer when appropriate.
- plus many other standard Scaffold properties like floatingActionButton, backgroundColor, endDrawer, etc., are passed through.
ResponsiveNavigationDestination #
A data class used to define each item in your navigation.
Properties:
- label: (required) String - The text label for the destination.
- icon: (required) IconData - The icon to display for the destination.
- selectedIcon: IconData? - An optional icon to display when this destination is selected (useful for BottomNavigationBar and NavigationRail).
- customLeading: Widget? - An optional widget to use as the leading element if this destination is rendered as a ListTile (e.g., in a Drawer).
- customTitle: Widget? - An optional widget to use as the title element if this destination is rendered as a ListTile. This allows for more complex titles, like including a Badge.
ResponsiveBreakpoints #
A simple class to define the screen width values at which the navigation UI changes.
Properties:
- small: double - The maximum width for the BottomNavigationBar to be shown. Devices smaller than or equal to this width use the bottom navigation. Defaults to 600.0.
- medium: double - The maximum width for the NavigationRail to be shown. Devices wider than small but smaller than or equal to this width use the navigation rail. Defaults to 960.0. Screens wider than medium will use the large screen navigation (persistent Drawer or the widget from largeScreenNavigationBuilder).
Advanced Usage #
Explore more powerful ways to customize and use the ResponsiveNavigationScaffold.
Customizing Navigation Elements
You can provide your own builder functions to take full control over the appearance and behavior of the BottomNavigationBar, NavigationRail, or the large screen navigation panel.
ResponsiveNavigationScaffold(
// ... other necessary properties
destinations: myDestinations,
selectedIndex: _selectedIndex,
onDestinationSelected: (i) => setState(() => _selectedIndex = i),
body: myBody,
bottomNavigationBarBuilder: (context, items, currentIndex, onTap) {
// 'items' is a List<BottomNavigationBarItem> generated from your destinations
return BottomNavigationBar(
items: items,
currentIndex: currentIndex,
onTap: onTap,
selectedItemColor: Colors.deepOrange,
unselectedItemColor: Colors.grey,
type: BottomNavigationBarType.fixed, // Or .shifting
);
},
navigationRailBuilder: (context, railDestinations, currentIndex, onTap, isExtended) {
// 'railDestinations' is a List<NavigationRailDestination> generated from your destinations
return NavigationRail(
destinations: railDestinations,
selectedIndex: currentIndex,
onDestinationSelected: onTap,
extended: isExtended,
minExtendedWidth: 200, // Customize extended width
leading: Column(
children: [
SizedBox(height: 20),
FlutterLogo(size: 40),
SizedBox(height: 20),
],
),
trailing: Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: IconButton(icon: Icon(Icons.logout), onPressed: () {}),
),
),
),
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
);
},
largeScreenNavigationBuilder: (context, drawerListTiles, currentIndex, onTap) {
// 'drawerListTiles' is a List<Widget> (typically ListTiles) generated from your destinations
return Material( // Use Material for proper theming and elevation
elevation: 1.0,
child: Container(
width: 256, // Desired width for your side panel
color: Theme.of(context).canvasColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0),
child: Text(
"Main Menu",
style: Theme.of(context).textTheme.titleLarge,
),
),
const Divider(),
Expanded(
child: ListView(
padding: EdgeInsets.zero,
children: drawerListTiles,
),
),
],
),
),
);
},
)
Tablet View: App Drawer vs. Side Bar #
This package helps you manage common tablet UI patterns
- Temporary App Drawer (e.g., for Settings, About):
-
Provide a standard Drawer widget to the drawer property of ResponsiveNavigationScaffold.
-
ResponsiveNavigationScaffold(drawer: MySettingsDrawer(), ...)
-
When autoAdjustAppBarLeading is true (default), a hamburger icon will typically appear in the AppBar on smaller screens (those using BottomNavigationBar or NavigationRail) to open this drawer.
-
This drawer remains temporary even on larger screens if your primary navigation is a custom side panel (via largeScreenNavigationBuilder that doesn't return a Drawer).
- Persistent Side Bar (for Primary Navigation on Large Screens):
-
Use the largeScreenNavigationBuilder property.
-
If this builder returns a widget that is not a standard Drawer (e.g., a Container, a custom SidePanelWidget), the package will arrange this widget in a Row alongside your main body content, creating a persistent side bar. This is ideal for primary navigation on tablet landscape, desktop, or web.
-
If largeScreenNavigationBuilder is not provided, or if it returns a Drawer widget, that Drawer will be used as the persistent primary navigation on large screens.
Example for Tablet (Landscape) with Persistent Side Bar & Temporary Settings Drawer:
ResponsiveNavigationScaffold(
// ... destinations, selectedIndex, body, etc. ...
appBar: AppBar(title: Text("Tablet App")),
drawer: MySettingsDrawer(), // For temporary settings
largeScreenNavigationBuilder: (context, primaryNavItems, currentIndex, onTap) {
return Container( // Your custom side panel for primary navigation
width: 240,
color: Colors.blueGrey.shade100,
child: ListView(children: primaryNavItems),
);
},
)
In this setup, the largeScreenNavigationBuilder provides the main, always-visible side navigation. The MySettingsDrawer() is still available and can be opened (e.g., via the AppBar's leading icon if autoAdjustAppBarLeading handles it, or via a custom button).
Please refer to the example/ directory in the repository for a more comprehensive application demonstrating these features.
Contributing #
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
Fork the Project #
Create your Feature Branch
git checkout -b feature/AmazingFeature
Commit your Changes
git commit -m 'Add some AmazingFeature'
Push to the Branch
git push origin feature/AmazingFeature
Open a Pull Request
License #
Distributed under the MIT License. See LICENSE file for more information. Repository: https://github.com/StephLak/responsive-navigation-scaffold