AdaptiveConvexNavigation is a self-contained, drop-in widget that automatically provides responsive navigation for your Flutter app. It intelligently switches between mobile and desktop layouts without requiring any manual responsive code.
Uses the beautiful ConvexAppBar at the bottom of the screen with its signature convex shape.
Uses NavigationRail on the side, providing a professional desktop experience.
- β Zero Configuration - Works out of the box with sensible defaults
- β Fully Customizable - All ConvexAppBar and NavigationRail properties available
- β Badge Support - Show notifications and counters on navigation items
- β All Styles - Supports all ConvexAppBar styles (react, fixed, circle, etc.)
- β Theming - Full theming support including gradients
- β Self-Contained - No need for LayoutBuilder or manual responsive code
- β Cross-Platform - Works seamlessly on iOS, Android, Web, and Desktop
import 'package:convex_bottom_bar_renew/convex_bottom_bar_renew.dart';
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return AdaptiveConvexNavigation(
selectedIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: const [
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.search, title: 'Search'),
TabItem(icon: Icons.person, title: 'Profile'),
],
child: Scaffold(
appBar: AppBar(title: const Text('My App')),
body: Center(child: Text('Page $_selectedIndex')),
),
);
}
}That's it! Your app now has responsive navigation. π
AdaptiveConvexNavigation(
selectedIndex: _selectedIndex,
onTap: _onNavigationItemSelected,
// Mobile styling
convexStyle: TabStyle.react,
backgroundColor: Colors.blue,
activeColor: Colors.white,
color: Colors.white70,
// Desktop styling (uses mobile colors as fallback)
railBackgroundColor: Colors.blue,
railSelectedIconTheme: const IconThemeData(color: Colors.white),
railUnselectedIconTheme: const IconThemeData(color: Colors.white70),
items: const [
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.search, title: 'Search'),
TabItem(icon: Icons.person, title: 'Profile'),
],
child: YourContentWidget(),
)AdaptiveConvexNavigation(
// Mobile: Fun, colorful convex bar
convexStyle: TabStyle.reactCircle,
backgroundColor: Colors.deepPurple,
gradient: LinearGradient(
colors: [Colors.purple, Colors.blue],
),
// Desktop: Professional, minimalist rail
railBackgroundColor: Colors.grey[900],
railLabelType: NavigationRailLabelType.selected,
railUseIndicator: true,
// ... rest of config
)Show notifications, counters, or indicators on your navigation items:
AdaptiveConvexNavigation.badge(
{
0: '5', // Text badge: "5 new items"
1: '99+', // Text badge: "99+ notifications"
2: Icons.circle, // Icon badge: simple dot indicator
},
selectedIndex: _selectedIndex,
onTap: _onNavigationItemSelected,
// Badge styling
badgeColor: Colors.red,
badgeTextColor: Colors.white,
badgePadding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
badgeMargin: const EdgeInsets.only(top: 8, right: 8),
badgeBorderRadius: 12,
// Navigation items
items: const [
TabItem(icon: Icons.message, title: 'Messages'),
TabItem(icon: Icons.notifications, title: 'Alerts'),
TabItem(icon: Icons.person, title: 'Profile'),
],
child: YourContentWidget(),
)Change when the layout switches:
AdaptiveConvexNavigation(
breakpoint: 800, // Switch at 800px instead of default 600px
// ... rest of config
)All standard ConvexAppBar features work in adaptive mode:
- β
Styles:
fixed,fixedCircle,react,reactCircle,textIn,titled,flip - β Theming: Colors, gradients, shadows
- β Customization: Height, curve size, elevation, corner radius
- β Badges: Custom badge builders
- β Controllers: TabController integration
- β Callbacks: onTap, onTapNotify
Full control over the desktop NavigationRail:
AdaptiveConvexNavigation(
// Rail-specific properties
railLabelType: NavigationRailLabelType.all, // none, selected, all
railExtended: false, // Expand rail to show labels inline
railUseIndicator: true, // Show selection indicator
railIndicatorColor: Colors.blue.shade100, // Indicator color
railLeading: MyLogoWidget(), // Widget at top of rail
railTrailing: MySettingsWidget(), // Widget at bottom of rail
railMinWidth: 72, // Minimum rail width
railElevation: 4, // Rail shadow elevation
// ... rest of config
)| Property | Type | Description |
|---|---|---|
child |
Widget | Required. The content to display in the main area |
items |
List<TabItem> | Required. Navigation items |
selectedIndex |
int | Required. Currently selected index |
onTap |
Function(int) | Callback when item is tapped |
breakpoint |
double | Screen width threshold (default: 600) |
| Property | Type | Description |
|---|---|---|
convexStyle |
TabStyle | Tab style (default: reactCircle) |
backgroundColor |
Color | Background color |
color |
Color | Inactive item color |
activeColor |
Color | Active item color |
gradient |
Gradient | Gradient background |
height |
double | AppBar height |
curveSize |
double | Convex curve size |
elevation |
double | Shadow elevation |
cornerRadius |
double | Corner radius (fixed styles) |
chipBuilder |
ChipBuilder | Custom badge builder |
| Property | Type | Description |
|---|---|---|
railBackgroundColor |
Color | Background color |
railLabelType |
NavigationRailLabelType | Label display type |
railSelectedIconTheme |
IconThemeData | Selected icon theme |
railUnselectedIconTheme |
IconThemeData | Unselected icon theme |
railUseIndicator |
bool | Show selection indicator |
railIndicatorColor |
Color | Indicator color |
railExtended |
bool | Expand rail width |
railLeading |
Widget | Widget at top |
railTrailing |
Widget | Widget at bottom |
railMinWidth |
double | Minimum width |
railElevation |
double | Shadow elevation |
// Automatically adapts between phone and tablet layouts
AdaptiveConvexNavigation(
breakpoint: 600, // Standard tablet breakpoint
// ... config
)// Responsive web app that works on all screen sizes
AdaptiveConvexNavigation(
breakpoint: 900, // Larger breakpoint for web
// ... config
)// One widget, works everywhere
AdaptiveConvexNavigation(
// iOS/Android: ConvexAppBar
// iPad/Tablet: NavigationRail
// Web/Desktop: NavigationRail
// ... config
)// OLD: Manual responsive layout (30+ lines)
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final isWideScreen = constraints.maxWidth >= 600;
if (isWideScreen) {
return Row(
children: [
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: _onNavigationItemSelected,
destinations: [
NavigationRailDestination(icon: Icon(Icons.home), label: Text('Home')),
NavigationRailDestination(icon: Icon(Icons.search), label: Text('Search')),
],
),
VerticalDivider(thickness: 1, width: 1),
Expanded(child: _buildContent()),
],
);
} else {
return Scaffold(
body: _buildContent(),
bottomNavigationBar: ConvexAppBar(
items: [
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.search, title: 'Search'),
],
initialActiveIndex: _selectedIndex,
onTap: _onNavigationItemSelected,
),
);
}
},
);
}// NEW: Clean, simple, self-contained (10 lines)
Widget build(BuildContext context) {
return AdaptiveConvexNavigation(
selectedIndex: _selectedIndex,
onTap: _onNavigationItemSelected,
items: const [
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.search, title: 'Search'),
],
child: _buildContent(),
);
}Result: 70% less code, easier to maintain, more features! π
| Platform | < Breakpoint | β₯ Breakpoint |
|---|---|---|
| iOS | ConvexAppBar | NavigationRail |
| Android | ConvexAppBar | NavigationRail |
| Web | ConvexAppBar | NavigationRail |
| macOS | ConvexAppBar | NavigationRail |
| Windows | ConvexAppBar | NavigationRail |
| Linux | ConvexAppBar | NavigationRail |
Check out the example app for complete demonstrations:
cd example
flutter runFiles:
example/lib/main.dart- Basic adaptive navigationexample/lib/adaptive_badge_example.dart- Advanced features with badges
Try it:
- Run the app
- Resize the window
- Watch the navigation adapt automatically!
Use the same colors for both layouts for a cohesive experience:
const primaryColor = Colors.blue;
const activeColor = Colors.white;
AdaptiveConvexNavigation(
backgroundColor: primaryColor,
railBackgroundColor: primaryColor,
activeColor: activeColor,
railSelectedIconTheme: IconThemeData(color: activeColor),
// ...
)- Mobile-first apps: 600px (default)
- Web apps: 900px or higher
- Tablet-optimized: 768px
While the widget adapts automatically, always test on:
- Small phones (< 400px)
- Large phones (400-600px)
- Tablets (600-900px)
- Desktop (> 900px)
The NavigationRail takes horizontal space. Ensure your content adapts:
child: Scaffold(
appBar: AppBar(title: const Text('My App')),
body: LayoutBuilder(
builder: (context, constraints) {
// Your content can also adapt based on available space
return YourResponsiveContent(width: constraints.maxWidth);
},
),
)Note: NavigationRail has limited badge support in the current implementation. Badges work fully on ConvexAppBar (mobile). Desktop badge support is planned for a future update.
Solution: Ensure the widget has access to the full screen width. If wrapped in a constrained container, it will use that width instead.
Solution: Set both mobile and desktop color properties explicitly:
backgroundColor: Colors.blue,
railBackgroundColor: Colors.blue,Same as the main package - Apache License 2.0
Found a bug or have a feature request? Please open an issue on GitHub!
Made with β€οΈ for the Flutter community