Search code examples
flutterbottomnavigationview

flutter bottom navigation bar styling problem


This is the bottom navigation I am trying to do.

How i can implement this bottom navigation bar? I tried curved bottom navigation but it did not give me the solution and I tried flutter bottom navigation bar with fab center docked, but that also didn't work.

this is the bottom navigation I am trying to do][1]how i can implements this bottom navigation bar i tried curved bottom navigation but did gave me the solution and i tried flutter bottom navigation bar with fab center docked but also didn't give me the solution if you can help me guys i would be thankful


Solution

  • Flutter has a specific shape for that kind of UI, it's called CircularNotchedRectangle. You can take the code of that class to see how the shape is drawn, build your custom shape from it, and tweak it to get the style you want, since it is pretty similar to CircularNotchedRectangle. I wrote a little snippet that you can run in DartPad for you to see how to implement this in a BottomNavigationBar. It might not be the exact same shape, but I think I got pretty close. It is impossible for me to get the exact shape without the parameters of that curve. Play around with the s1, s2, and addedRadius parameters to get exactly what you want:

    import 'dart:math' as math;
    
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class CustomNotchedRectangle extends NotchedShape {
      const CustomNotchedRectangle();
    
      @override
      Path getOuterPath(Rect host, Rect guest) {
        if (guest == null || !host.overlaps(guest)) return Path()..addRect(host);
    
        const double s1 = 10.0;
        const double s2 = 8.0;
        const double addedRadius = 3;
    
        final double notchRadius = guest.width / 2.0 + addedRadius;
        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>(6);
    
        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[0].dx, p[0].dy)
          ..quadraticBezierTo(p[1].dx, p[1].dy, p[2].dx, p[2].dy)
          ..arcToPoint(
            p[3],
            radius: Radius.circular(notchRadius),
            clockwise: false,
          )
          ..quadraticBezierTo(p[4].dx, p[4].dy, p[5].dx, p[5].dy)
          ..lineTo(host.right, host.top)
          ..lineTo(host.right, host.bottom)
          ..lineTo(host.left, host.bottom)
          ..close();
      }
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Sample Code'),
          ),
          body: Center(
            child: Text('You have pressed the button $_counter times.'),
          ),
          bottomNavigationBar: BottomAppBar(
            shape: const CustomNotchedRectangle(),
            child: Container(height: 50.0, color: Theme.of(context).primaryColor),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment Counter',
            child: Icon(Icons.add),
          ),
          floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        );
      }
    }
    

    Here is the result:

    Custom Shape Example