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

  1. 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

Page One Page Two Page Three Page Four