Skip to main content

floating_bottom_nav_bar 1.1.4 copy "floating_bottom_nav_bar: ^1.1.4" to clipboard
floating_bottom_nav_bar: ^1.1.4 copied to clipboard

A customizable floating bottom navigation bar for Flutter with smooth animations, modern UI styling, SVG icon support, and badge indicators.

example/main.dart

import 'package:floating_frosted_bottom_bar/app/frosted_bottom_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Floating Bottom Nav Bar Demo',
      theme: ThemeData(
        primarySwatch: Colors.purple,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MainScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> with TickerProviderStateMixin {
  final BaseController controller = Get.put(BaseController());
  late TabController _tabController;

  final List<Widget> tabPages = [
    HomePage(),
    BrowsePage(),
    MapsPage(),
    FavoritePage(),
    MorePage(),
  ];

  @override
  void initState() {
    _tabController = TabController(length: 5, vsync: this);
    _tabController.animation!.addListener(() {
      final value = _tabController.animation!.value.round();
      if (value != controller.currentPage.value && mounted) {
        controller.setPage(value);
      }
    });
    super.initState();
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: SafeArea(
        bottom: false,
        child: Obx(() => IndexedStack(
          index: controller.currentPage.value,
          children: tabPages,
        )),
      ),
      bottomNavigationBar: FrostedBottomBar(
        opacity: 1.0,
        sigmaX: 5,
        sigmaY: 5,
        borderRadius: BorderRadius.circular(16),
        duration: const Duration(milliseconds: 800),
        hideOnScroll: true,
        body: (context, scrollController) => TabBarView(
          controller: _tabController,
          physics: const BouncingScrollPhysics(),
          children: tabPages,
        ),
        child: Container(
          width: double.infinity,
          color: const Color(0xFFb22222),
          child: TabBar(
            controller: _tabController,
            onTap: (index) {
              controller.setPage(index);
            },
            indicatorPadding: const EdgeInsets.fromLTRB(6, 60, 6, 3),
            indicator: CurvedUnderlineTabIndicator(
              color: Colors.white,
              height: 10,
              width: 60,
              radius: 30,
            ),
            tabs: [
              TabsIconWithLabel(
                assetPath: "assets/icons/home.svg",
                label: "Home",
                color: controller.currentPage.value == 0
                    ? Colors.yellow.shade50
                    : Colors.yellow.shade50,
              ),
              TabsIconWithLabel(
                assetPath: "assets/icons/browse.svg",
                label: "Browse",
                color: controller.currentPage.value == 1
                    ? Colors.yellow.shade50
                    : Colors.yellow.shade50,
              ),
              TabsIconWithLabel(
                assetPath: "assets/icons/maps.svg",
                label: "Maps",
                color: controller.currentPage.value == 2
                    ? Colors.yellow.shade50
                    : Colors.yellow.shade50,
              ),
              TabsIconWithLabel(
                assetPath: "assets/icons/favorite.svg",
                label: "Favorites",
                color: controller.currentPage.value == 3
                    ? Colors.yellow.shade50
                    : Colors.yellow.shade50,
              ),
              TabsIconWithLabel(
                assetPath: "assets/icons/more.svg",
                label: "More",
                color: controller.currentPage.value == 4
                    ? Colors.yellow.shade50
                    : Colors.yellow.shade50,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// Controller for managing page state
class BaseController extends GetxController {
  var currentPage = 0.obs;

  void setPage(int page) {
    currentPage.value = page;
  }
}

// Tab icon widget
class TabsIconWithLabel extends StatelessWidget {
  final Color color;
  final double iconSize;
  final String assetPath;
  final String label;

  const TabsIconWithLabel({
    Key? key,
    this.color = Colors.white,
    this.iconSize = 34,
    required this.assetPath,
    required this.label,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Tab(
      iconMargin: const EdgeInsets.only(top: 18.0, bottom: 5),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SvgPicture.asset(
            assetPath,
            color: color,
            width: iconSize,
            height: iconSize,
          ),
          const SizedBox(height: 5),
          Text(
            label,
            style: TextStyle(
              fontFamily: 'Montserrat',
              fontWeight: FontWeight.normal,
              color: color,
              fontSize: 7,
            ),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

// Custom tab indicator
class CurvedUnderlineTabIndicator extends Decoration {
  final Color color;
  final double height;
  final double width;
  final double radius;

  const CurvedUnderlineTabIndicator({
    required this.color,
    required this.height,
    required this.width,
    required this.radius,
  });

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    return _CurvedUnderlinePainter(color, height, width, radius);
  }
}

class _CurvedUnderlinePainter extends BoxPainter {
  final Color color;
  final double height;
  final double width;
  final double radius;

  _CurvedUnderlinePainter(this.color, this.height, this.width, this.radius);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill;

    final rect = Rect.fromLTWH(
      offset.dx + (configuration.size!.width - width) / 2,
      configuration.size!.height - height,
      width,
      height,
    );

    final rRect = RRect.fromRectAndRadius(rect, Radius.circular(radius));
    canvas.drawRRect(rRect, paint);
  }
}

// Example pages
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: const Center(
        child: Text(
          'Home Page',
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

class BrowsePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: const Center(
        child: Text(
          'Browse Page',
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

class MapsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: const Center(
        child: Text(
          'Maps Page',
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

class FavoritePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: const Center(
        child: Text(
          'Favorites Page',
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

class MorePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: const Center(
        child: Text(
          'More Page',
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}
1
likes
135
points
45
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A customizable floating bottom navigation bar for Flutter with smooth animations, modern UI styling, SVG icon support, and badge indicators.

Homepage

License

unknown (license)

Dependencies

badges, cupertino_icons, floating_frosted_bottom_bar, flutter, flutter_svg, get

More

Packages that depend on floating_bottom_nav_bar