Curve Bottom Nav Bar
A highly customizable, animated bottom navigation bar with a central floating action notch and smooth curved background. Designed for apps that want a playful yet production‑ready nav experience.
✨ Features
1.Curved background with configurable height, radius, and notch size
2.Central floating action (FAB-style) with a dedicated callback
3.Active/inactive icon coloring and index management
4.Smooth tap handling with page switching
5.Works with any list of icons and destination widgets
6.Null-safe, lightweight, and easy to drop into existing apps
7.Curved background: A modern curved design that gives your app a sleek and dynamic look.
8.Configurable height, radius, and notch size: Fine‑tune the geometry of the bar to match your design requirements.
9.Central floating action (FAB-style): Highlight a primary action with a center notch and floating icon, ideal for send, compose, or scan actions.
10.Customizable colors: Control active/inactive tab colors and background curve color for consistent theming.
11.Page navigation support: Tap handling with callbacks for smooth switching between multiple pages.
12.Lightweight & null-safe: Built with modern Flutter guidelines for efficiency and reliability.
13.Flexible state management: Use with setState, PageView, or integrate with state management solutions like GetX, Provider, or Bloc.
14.Accessibility-friendly: Add tooltips or semantics to make the navigation bar inclusive.
📦 Getting started
- Install Add the package to your pubspec.yaml:
dependencies:
curve_bottom_nav_bar: ^0.0.1
Then run: flutter pub get Import
import 'package:curve_bottom_nav_bar/curve_bottom_nav_bar.dart';
Note: If you’re using a local package path or a different name/structure, match your actual import paths.
📦 Getting started
import 'package:flutter/material.dart';
import 'package:curve_bottom_nav_bar/curve_bottom_nav_bar.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final iconData = [
Icons.home,
Icons.shopping_bag,
Icons.read_more,
Icons.receipt,
];
final pages = [PageOne(), PageTwo(), PageThree(), PageFour()];
int activeIndex = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: CurveBottomNavBar(
activeColor: Colors.yellow,
activeIndex: activeIndex,
centerFloatIcon: Icon(Icons.send),
curveColor: Color(0xFF8C4EF8),
curveHeight: 65,
curveNotch: 38,
curveRadius: 40,
inActiveColor: Colors.grey,
iconData: iconData.map((e) => Icon(e)).toList(),
widget: pages,
onCenterFloatingTab: () {
print("send float tab");
},
onContentTap: (int index) {
setState(() {
activeIndex = index;
});
},
),
);
}
}
class PageOne extends StatelessWidget {
const PageOne({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Center(child: Text("Page One"))],
),
);
}
}
class PageTwo extends StatelessWidget {
const PageTwo({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Center(child: Text("Page Two"))],
),
);
}
}
class PageThree extends StatelessWidget {
const PageThree({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Center(child: Text("Page Three"))],
),
);
}
}
class PageFour extends StatelessWidget {
const PageFour({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Center(child: Text("Page Four"))],
),
);
}
}
Constructor
CurveBottomNavBar({
// Colors
required Color activeColor,
required Color inActiveColor,
required Color curveColor,
// Geometry & layout
double curveHeight = 60,
double curveNotch = 36,
double curveRadius = 32,
// Content
required List<Widget> iconData,
required List<Widget> widget,
Widget? centerFloatIcon,
// State
required int activeIndex,
// Callbacks
VoidCallback? onCenterFloatingTab,
ValueChanged<int>? onContentTap,
})
Parameters (detailed)
1.activeColor (Color, required) → Color applied to the active tab/icon.
2.inActiveColor (Color, required) → Color applied to all inactive tabs/icons.
3.curveColor (Color, required) → Background color of the curved bar.
4.curveHeight (double, optional, default: 60) → Total height of the curved nav bar. Increase for taller UI.
5.curveNotch (double, optional, default: 36) → Diameter/size of the center notch where the floating icon sits.
6.curveRadius (double, optional, default: 32) → Corner radius of the bar’s top edges and curve transitions.
7.iconData (List<Widget>, required) → Icons for each tab. Typically a list of Icon widgets. Length must match widget.length.
8.widget (List<Widget>, required) → Destination pages for each tab. Display them in Scaffold.body or manage via a PageView.
9.centerFloatIcon (Widget?, optional, default: null) → Widget shown in the center notch (e.g., Icon or CircleAvatar). If null, the notch remains empty/inactive.
10.activeIndex (int, required) → The index of the selected tab. You control this from your state.
11.onCenterFloatingTab (VoidCallback?, optional, default: null) → Called when the center floating icon is tapped. Use for quick actions (send, compose, scan, etc.).
12.onContentTap (ValueChanged<int>?, optional, default: null) → Called when a tab icon is tapped. Update your activeIndex here.
Output
![]() |
![]() |
![]() |
![]() |



