flutter bottom navigation bar styling problem

2,693

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

Share:
2,693
Ghaith Chamieh
Author by

Ghaith Chamieh

Updated on December 13, 2022

Comments

  • Ghaith Chamieh
    Ghaith Chamieh over 1 year

    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

    • Bhargav Sejpal
      Bhargav Sejpal about 4 years
    • drogel
      drogel about 4 years
      You mean that shape is not exactly the same as that of CircularNotchedRectangle?
    • Ghaith Chamieh
      Ghaith Chamieh about 4 years
      when using curved_navigation_bar first of all i only have height of 75 , i can't customize the selected index and i can't anything behind the selected index which is not acceptable in this design i tried to use curved navigation I either used it wrong or it couldn't serve me well
    • Ghaith Chamieh
      Ghaith Chamieh about 4 years
      I meant i have 2 cases the unselected icon and the selected icon i should apply orange container to the selected icon which i can't do, also i want to see the screen behind the bottom navigation bar which I tried but i couldn't do that either
  • Ghaith Chamieh
    Ghaith Chamieh about 4 years
    I tried it but look at the curve it dose not looks like the photo i tried to change the curve layout but i couldn't... if you have any idea about changing the curve layout that would solve my problem
  • drogel
    drogel about 4 years
    Okay, I see. Please review my edited answer, I think it might be useful for you.
  • Ghaith Chamieh
    Ghaith Chamieh about 4 years
    yes it is thx a-lot man even though i didn't understand the math but that brilliant