Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make custom Bottom Navigation Bar in Flutter

I have a design of Bottom Navigation Bar like this:

enter image description here

I try my best to create custom of Bottom Navigation Bar with this code:

class FABBottomAppBarItem {
  FABBottomAppBarItem({this.iconData, this.text});
  IconData iconData;
  String text;
}

class FABBottomAppBar extends StatefulWidget {
  FABBottomAppBar({
    this.items,
    this.centerItemText,
    this.height: 60.0,
    this.iconSize: 24.0,
    this.backgroundColor,
    this.color,
    this.selectedColor,
    this.notchedShape,
    this.onTabSelected,
  }) {
    assert(this.items.length == 2 || this.items.length == 4);
  }
  final List<FABBottomAppBarItem> items;
  final String centerItemText;
  final double height;
  final double iconSize;
  final Color backgroundColor;
  final Color color;
  final Color selectedColor;
  final NotchedShape notchedShape;
  final ValueChanged<int> onTabSelected;

  @override
  State<StatefulWidget> createState() => FABBottomAppBarState();
}

class FABBottomAppBarState extends State<FABBottomAppBar> {
  int _selectedIndex = 0;

  _updateIndex(int index) {
    widget.onTabSelected(index);
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> items = List.generate(widget.items.length, (int index) {
      return _buildTabItem(
        item: widget.items[index],
        index: index,
        onPressed: _updateIndex,
      );
    });
    items.insert(items.length >> 1, _buildMiddleTabItem());

    return BottomAppBar(
      shape: widget.notchedShape,
      child: Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: items,
      ),
      color: widget.backgroundColor,
    );
  }

  Widget _buildMiddleTabItem() {
    return Expanded(
      child: SizedBox(
        height: widget.height,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(height: widget.iconSize),
            Text(
              widget.centerItemText ?? '',
              style: TextStyle(color: widget.color),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildTabItem({
    FABBottomAppBarItem item,
    int index,
    ValueChanged<int> onPressed,
  }) {
    Color color = _selectedIndex == index ? widget.selectedColor : widget.color;
    return Expanded(
      child: SizedBox(
        height: widget.height,
        child: Material(
          type: MaterialType.transparency,
          child: InkWell(
            onTap: () => onPressed(index),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Icon(item.iconData, color: color, size: widget.iconSize),
                Text(
                  item.text,
                  style: TextStyle(color: color),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

And I implemented that custom like this:

bottomNavigationBar: FABBottomAppBar(
          centerItemText: 'เสา',
          color: Colors.grey,
          backgroundColor: Colors.white,
          selectedColor: Colors.red,
          notchedShape: CircularNotchedRectangle(),
          onTabSelected: _onTapped,
          items: [
            FABBottomAppBarItem(iconData: Icons.home, text: 'หน้าแรก'),
            FABBottomAppBarItem(iconData: Icons.search, text: 'ค้นหา'),
            FABBottomAppBarItem(iconData: Icons.account_circle, text: 'โปรไฟล์'),
            FABBottomAppBarItem(iconData: Icons.more_horiz, text: 'อื่นๆ'),
          ],
        ),
        body: _list[_page],
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        floatingActionButton: FloatingActionButton(
          onPressed: () {
          },
          child: Icon(Icons.add),
          elevation: 2.0,
        ),
      ),

And the result of that code is:

enter image description here

How to make my Custom Nav Bar like the design? Because in the design, the FAB/Asset/Icon inside the Bottom Navigation Bar and have curved upwards as I marked with arrows in the design.

like image 346
R Rifa Fauzi Komara Avatar asked Jan 20 '20 08:01

R Rifa Fauzi Komara


People also ask

How do you customize the bottom nav bar flutter?

Now let's create our bottom navigation bar. In the HomePage class let's define the bottomNavigationBar attribute and assign a Container to it. Give it a height of 60 with some BoxDecoration (Pixels) add a Row as the child of the Container. Set the main axis alignment to space around.

How do you make the bottom tab bar in flutter?

Showing BottomNavigationBar Scaffold( appBar: AppBar( title: const Text('BottomNavigationBar Demo'), ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons. call), label: 'Calls', ), BottomNavigationBarItem( icon: Icon(Icons.

How do I put the bottom navigation bar in all screen in flutter?

You can use IndexedStack to persist State when you change the page. persistent_bottom_nav_bar manage the Navigation stack of individual tabs and using this library you can manage hide/show BottomNavigationBar.


2 Answers

I edited CircularNotchedRectangle.

Use CircularOuterNotchedRectangle instead of CircularNotchedRectangle.

PS. I added extraOffset param for extra thick. but it's not working exactly correct. But I just wanted to show you how to approach.

class CircularOuterNotchedRectangle extends NotchedShape {
  /// Creates a [CircularOuterNotchedRectangle].
  ///
  /// The same object can be used to create multiple shapes.
  const CircularOuterNotchedRectangle({this.extraOffset = 10.0});

  final double extraOffset;

  /// Creates a [Path] that describes a rectangle with a smooth circular notch.
  ///
  /// `host` is the bounding box for the returned shape. Conceptually this is
  /// the rectangle to which the notch will be applied.
  ///
  /// `guest` is the bounding box of a circle that the notch accommodates. All
  /// points in the circle bounded by `guest` will be outside of the returned
  /// path.
  ///
  /// The notch is curve that smoothly connects the host's top edge and
  /// the guest circle.
  // TODO(amirh): add an example diagram here.
  @override
  Path getOuterPath(Rect host, Rect guest) {
    if (guest == null || !host.overlaps(guest)) return Path()..addRect(host);

    // The guest's shape is a circle bounded by the guest rectangle.
    // So the guest's radius is half the guest width.
    final double notchRadius = guest.width / 2.0;

    // We build a path for the notch from 3 segments:
    // Segment A - a Bezier curve from the host's top edge to segment B.
    // Segment B - an arc with radius notchRadius.
    // Segment C - a Bezier curve from segment B back to the host's top edge.
    //
    // A detailed explanation and the derivation of the formulas below is

    const double s1 = 15.0;
    const double s2 = 1.0;

    final double r = notchRadius + extraOffset/2;
    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) - extraOffset/2;
    final double p2yB = math.sqrt(r * r - p2xB * p2xB) - extraOffset/2;

    final List<Offset> p = List<Offset>(6);

    // p0, p1, and p2 are the control points for segment A.
    p[0] = Offset(a - s1, b);
    p[1] = Offset(a, b);
    p[2] = p2yA > p2yB ? Offset(p2xA, -p2yA) : Offset(p2xB, p2yB);

    // p3, p4, and p5 are the control points for segment B, which is a mirror
    // of segment A around the y axis.
    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);

    // translate all points back to the absolute coordinate system.
    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: true,
      )
      ..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();
  }
}

like image 143
Bansook Nam Avatar answered Oct 10 '22 08:10

Bansook Nam


Please try this one, its may helps you

 Scaffold(
    backgroundColor: Colors.blueAccent,
    floatingActionButton: Padding(
      padding: EdgeInsets.only(top: 20),
      child: SizedBox(
        height: 70,
        width: 70,
        child: FloatingActionButton(
          backgroundColor: Colors.transparent,
          elevation: 0,
          onPressed: () {},
          child: Container(
            height: 75,
            width: 75,
            decoration: BoxDecoration(
              border: Border.all(color: Colors.white, width: 4),
              shape: BoxShape.circle,
             color: Colors.red
            ),
            child: Icon(Icons.add, size: 40),
          ),
        ),
      ),
    ),
    floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    bottomNavigationBar: new Container(
      height: 80.0,
      color: Colors.white,
      padding: new EdgeInsets.only(top: 20.0),
      child: new Theme(

        data: Theme.of(context).copyWith(
          // sets the background color of the `BottomNavigationBar`
            canvasColor: Colors.white,
            // sets the active color of the `BottomNavigationBar` if `Brightness` is light
            primaryColor: Colors.red,
            bottomAppBarColor: Colors.green,
            textTheme: Theme
                .of(context)
                .textTheme
                .copyWith(caption: new TextStyle(color: Colors.grey))), // sets the inactive color of the `BottomNavigationBar`
        child:
        new BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            currentIndex:0 ,
            items: [
              BottomNavigationBarItem(
                  icon: new Icon(Icons.home),
                  title: new Text('Home'),
                  backgroundColor: Colors.black
              ),
              BottomNavigationBarItem(
                icon: new Icon(Icons.search),
                title: new Text('Search'),
              ),
BottomNavigationBarItem(
                  icon: Icon(Icons.bookmark_border,color: Colors.transparent,),
                  title: Text('Center')
              ),

              BottomNavigationBarItem(
                  icon: Icon(Icons.perm_identity),
                  title: Text('Person')
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.more_horiz),
                  title: Text('More')
              ),

            ]),
      ),
    ),
  )
like image 4
Avinash Avatar answered Oct 10 '22 10:10

Avinash