Ultra custom Bottom Navbar

 




import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:walletapp/const/colors.dart';
import 'package:walletapp/screens/analyics%20screen/analyics_screen.dart';
import 'package:walletapp/screens/home%20screen/home_screen.dart';
import 'package:walletapp/screens/profile%20screen/profile_screen.dart';
import 'package:walletapp/screens/settings%20screen/settings_screen.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;

  static const List<Widget> _pages = <Widget>[
    HomeScreen(),
    AnalyicsScreen(),
    HomeScreen(),
    SettingsScreen(),
    ProfileScreen(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_selectedIndex],
      bottomNavigationBar: BottomAppBar(
        shape: MyShape(),
        elevation: 0,
        notchMargin: 0.0,
        color: Colors.white,
        child: SizedBox(
          height: 50.0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              buildNavItem('assets/bottomNavbarIcons/home.svg',
                  'assets/bottomNavbarIcons/home_active.svg', 0),
              buildNavItem('assets/bottomNavbarIcons/report.svg',
                  'assets/bottomNavbarIcons/report_active.svg', 1),
              buildNavItem('assets/bottomNavbarIcons/home.svg',
                  'assets/bottomNavbarIcons/home_active.svg', 2),
              buildNavItem('assets/bottomNavbarIcons/settings.svg',
                  'assets/bottomNavbarIcons/settings_active.svg', 3),
              buildNavItem('assets/bottomNavbarIcons/user.svg',
                  'assets/bottomNavbarIcons/user_active.svg', 4),
            ],
          ),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(0.0),
        child: FloatingActionButton(
          elevation: 0,
          onPressed: () {
            Navigator.pushNamed(context, '/addTileScreen');
          },
          backgroundColor: mainColor,
          shape: const CircleBorder(),
          child: const Icon(
            Icons.add,
            size: 31,
            color: whiteColor,
          ),
        ),
      ),
    );
  }

  Widget buildNavItem(String assetName, String activeAssetName, int index) {
    return index == 2
        ? SizedBox(width: 60.0)
        : IconButton(
            icon: SvgPicture.asset(
              _selectedIndex == index ? activeAssetName : assetName,
              height: 26.0,
              width: 26,
              color: mainColor,
            ),
            onPressed: () => _onItemTapped(index),
          );
  }
}

class MyShape extends CircularNotchedRectangle {
  @override
  Path getOuterPath(Rect host, Rect? guest) {
    if (guest == null || !host.overlaps(guest)) return Path()..addRect(host);
    final double notchRadius = guest.width / 2.0;

    const double s1 = 8.0;
    const double s2 = 1.0;

    final double r = notchRadius;
    final double a = -1.0 * r - s2;
    final double b = host.top - guest.center.dy;

    final double n2 = math.sqrt(b * b * r * r * (a * a + b * b - r * r));
    final double p2xA = ((a * r * r) - n2) / (a * a + b * b);
    final double p2xB = ((a * r * r) + n2) / (a * a + b * b);
    final double p2yA = math.sqrt(r * r - p2xA * p2xA);
    final double p2yB = math.sqrt(r * r - p2xB * p2xB);

    final List<Offset> p = List<Offset>.filled(6, Offset.zero);

    p[0] = Offset(a - s1, b);
    p[1] = Offset(a, b);
    final double cmp = b < 0 ? -1.0 : 1.0;
    p[2] = cmp * p2yA > cmp * p2yB ? Offset(p2xA, -p2yA) : Offset(p2xB, p2yB);

    p[3] = Offset(-1.0 * p[2].dx, p[2].dy);
    p[4] = Offset(-1.0 * p[1].dx, p[1].dy);
    p[5] = Offset(-1.0 * p[0].dx, p[0].dy);

    for (int i = 0; i < p.length; i += 1) p[i] += guest.center;
    return Path()
      ..moveTo(host.left, host.top)
      ..lineTo(p[1].dx, p[1].dy)
      ..arcToPoint(
        p[4],
        radius: Radius.circular(notchRadius),
        clockwise: true,
      )
      ..lineTo(host.right, host.top)
      ..lineTo(host.right, host.bottom)
      ..lineTo(host.left, host.bottom)
      ..close();
  }
}




Comments