5

I am a novice while working with Flutter CustomPainter. I am trying to implement a BottomNavigationBar like the image provided below.

BottomNavigationBar with Path clipped at the middle and without animation

The BottomNavigationBar is static. There is no animation or change in the curve while clicking on the buttons. And there is no transition of pages.

I tried with some packages, but they either have an animation to the BottomNavigationBar or do not have the curve. And the buttons are asset images.

Please, help me here to implement the design.

5
  • 2
    Refer this answer Commented Nov 13, 2024 at 5:05
  • The reference is a very good solution. However, when I try to add the text, it causes issues like positioning and height-width overflow. @RavindraS.Patil Commented Nov 13, 2024 at 7:48
  • Just managed it using SizedBox Commented Nov 13, 2024 at 10:30
  • I've updated my answer @MehediHasan to address the requirements
    – DevQt
    Commented Nov 18, 2024 at 14:59
  • Does How to make bottomNavigationBar notch answer your question? if not please consider including minimal error reproducible code-example Commented Nov 19, 2024 at 3:24

1 Answer 1

3
+50

I hope you consider this one,

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

/// Flutter code sample for [FloatingActionButton].

void main() {
  runApp(const FloatingActionButtonExampleApp());
}

class FloatingActionButtonExampleApp extends StatelessWidget {
  const FloatingActionButtonExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const FloatingActionButtonExample(),
    );
  }
}

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

  @override
  State<FloatingActionButtonExample> createState() =>
      _FloatingActionButtonExampleState();
}

class _FloatingActionButtonExampleState
    extends State<FloatingActionButtonExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FloatingActionButton Sample'),
      ),
      body: const Center(child: Text('Press the button below!')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            debugPrint('Hi I am DevQt');
          });
        },
        shape: RoundedRectangleBorder(
          side: BorderSide(color: Colors.transparent, width: 2.0),
          borderRadius: BorderRadius.circular(50),
        ),
        child: const Icon(
          CupertinoIcons.stop,
          grade: 5.0,
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: BottomAppBar(
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: SizedBox(
          height: 50.0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.topLeft,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.speaker),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Text(
                    'End Session',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.video_camera),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

The code wasn't originally mine; I just used a source code from FloatingActionButton class for the instant implementation of the widget and Flutter 3.10: Floating Action Buttons for achieving the FloatingActionButton with notched BottomNavigationBar. Then I just play around with the code XD.

And this is the design output:

output

Update

To follow these requirements:

The answer must reflect the UI design from the image provided. The bottom navigation bar is 67px high, and with the top button, it is 102px in total. It should not break or overflow.

I refactored the code into:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

/// Flutter code sample for [FloatingActionButton].

void main() {
  runApp(const FloatingActionButtonExampleApp());
}

class FloatingActionButtonExampleApp extends StatelessWidget {
  const FloatingActionButtonExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const FloatingActionButtonExample(),
    );
  }
}

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

  @override
  State<FloatingActionButtonExample> createState() =>
      _FloatingActionButtonExampleState();
}

class _FloatingActionButtonExampleState
    extends State<FloatingActionButtonExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FloatingActionButton Sample'),
      ),
      body: const Center(child: Text('Press the button below!')),
      floatingActionButton: SizedBox(
        height: 35, // as per requirements and to achieve a rounded appearance
        width: 35, // as per requirements and to achieve a rounded appearance
        child: FloatingActionButton(
          onPressed: () {
            setState(() {
              debugPrint('Hi I am DevQt');
            });
          },
          shape: RoundedRectangleBorder(
            side: BorderSide(color: Colors.transparent, width: 2.0),
            borderRadius: BorderRadius.circular(35),
          ),
          child: const Icon(
            CupertinoIcons.stop,
            grade: 5.0,
          ),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: BottomAppBar(
        height: 67.0, // as per requirements
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Align(
              alignment: Alignment.topLeft,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: IconButton(
                  iconSize: 25,
                  onPressed: () {},
                  icon: Icon(CupertinoIcons.speaker),
                ),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: Text(
                  'End Session',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
              ),
            ),
            Align(
              alignment: Alignment.topRight,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                child: IconButton(
                  iconSize: 25,
                  onPressed: () {},
                  icon: Icon(CupertinoIcons.video_camera),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

I did a simple arithmetic on this but for the corresponding widget only, a bottom navigation bar 67px high and the top button 35px high (without mentioning the width to maintain the UI aesthetic to appear as a circular button) to get a total of 102px. Don't mind the

notchMargin: 6.0

because it doesn't affect your fixed total height of 102px (i.e., a combination of the bottom navigation bar and top button)

I tested out with the Google Chrome browser using the developer tools in a device mode:

For Mobile S - 320px resolution

mobile-s-320px-res

For Mobile M - 375px resolution

mobile-s-375px-res

For Mobile S - 425px resolution

mobile-s-425px-res

And if you still want to make things responsive (i.e., It should not break or overflow) from which you want to...

floating_button

Then, you may apply these code changes if so:

bottomNavigationBar: BottomAppBar(
        height: 67.0,
        notchMargin: 6.0,
        shape: const CircularNotchedRectangle(),
        color: Colors.amberAccent,
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.topLeft,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.speaker),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Text(
                    'End Session',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: IconButton(
                    iconSize: 25,
                    onPressed: () {},
                    icon: Icon(CupertinoIcons.video_camera),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
6
  • I have tried BottomAppBar. I did not find properties to curve the corners of the BottomAppBa, and the shadow property does not match the design. Commented Nov 18, 2024 at 15:16
  • Kindly apply the portion of the code from the stackoverflow.com/questions/79183398/…
    – DevQt
    Commented Nov 18, 2024 at 15:19
  • If you properly follow the source code I've provided, you'll get what you need (i.e., desired output). But you need to accept the fact that you have to do your part if you have other concerns that are unrelated to the given problem here.
    – DevQt
    Commented Nov 18, 2024 at 15:24
  • I need to be specific here; I mean the source code I've modified XD
    – DevQt
    Commented Nov 19, 2024 at 13:28
  • 1
    I don't think I would get the output like the image without CustomPainter. I tried wrapping it with a Container and providing shadows and circular borders. However, It takes the shadow to the middle button like a straight line. Commented Nov 19, 2024 at 15:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.