Custom shape of PopupMenuButton in flutter

2,907

You can create a shape for your custom PopupMenuButton.

Sample...

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          PopupMenuButton(
            offset: Offset(0, 50),
            shape: const TooltipShape(),
            itemBuilder: (_) => <PopupMenuEntry>[
              PopupMenuItem(
                  child: ListTile(
                leading: const Icon(Icons.calculate_outlined),
                title: const Text('Tax & Additional Charges'),
              )),
              PopupMenuItem(
                  child: ListTile(
                leading: const Icon(Icons.av_timer_outlined),
                title: const Text('Hold This Invoice'),
              )),
            ],
          ),
        ],
      ),
    );
  }
}

/// I'm using [RoundedRectangleBorder] as my reference...
class TooltipShape extends ShapeBorder {
  const TooltipShape();

  final BorderSide _side = BorderSide.none;
  final BorderRadiusGeometry _borderRadius = BorderRadius.zero;

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.all(_side.width);

  @override
  Path getInnerPath(
    Rect rect, {
    TextDirection? textDirection,
  }) {
    final Path path = Path();

    path.addRRect(
      _borderRadius.resolve(textDirection).toRRect(rect).deflate(_side.width),
    );

    return path;
  }

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    final Path path = Path();
    final RRect rrect = _borderRadius.resolve(textDirection).toRRect(rect);

    path.moveTo(0, 10);
    path.quadraticBezierTo(0, 0, 10, 0);
    path.lineTo(rrect.width - 30, 0);
    path.lineTo(rrect.width - 20, -10);
    path.lineTo(rrect.width - 10, 0);
    path.quadraticBezierTo(rrect.width, 0, rrect.width, 10);
    path.lineTo(rrect.width, rrect.height - 10);
    path.quadraticBezierTo(
        rrect.width, rrect.height, rrect.width - 10, rrect.height);
    path.lineTo(10, rrect.height);
    path.quadraticBezierTo(0, rrect.height, 0, rrect.height - 10);

    return path;
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}

  @override
  ShapeBorder scale(double t) => RoundedRectangleBorder(
        side: _side.scale(t),
        borderRadius: _borderRadius * t,
      );
}
Share:
2,907
Majid Ali
Author by

Majid Ali

Updated on December 01, 2022

Comments

  • Majid Ali
    Majid Ali over 1 year

    I wan to change the shape of my PopupMenuButton in flutter, want to add a triangle on top as shown in below picture, I have spent a lot of time on google but no achievement please help me out I am new to flutter so I do not know how to change this default container, now it simply has white rounded container, white arrow/triangle is not being added on top of it. please help out, thanks in advance

     popUpMenu= PopupMenuButton<String>(
         key: _menuKey,
         offset: Offset(50,100),
         padding: EdgeInsets.all(0.0),
         onSelected: (value) {
           if (value == "Tax & Additional Charges") {
             endDrawerController.drawerKey.value =
                 EndDrawerKeys.TaxAndAdditionalChargesEndDrawer;
             endDrawerController.scaffoldKey.currentState.openEndDrawer();
             print("Entering in tax");
           } else if (value == "Hold this Invoice") {
             endDrawerController.drawerKey.value =
                 EndDrawerKeys.HoldInvoiceEndDrawer;
             endDrawerController.scaffoldKey.currentState.openEndDrawer();
           }
         },
         shape: RoundedRectangleBorder(
             borderRadius: BorderRadius.all(Radius.circular(10.h))),
         itemBuilder: (context) => [
           PopupMenuItem(
             value: "Tax & Additional Charges",
             child: popUpMenuSingleItem(
                 icon: AppAssets.DeliveryIcon,
                 text: "Tax & Additional Charges",
                 topMargin: 15.h),
           ),
           PopupMenuItem(
             value: "Hold this Invoice",
             child: popUpMenuSingleItem(
                 icon: AppAssets.DeliveryIcon,
                 text: "Hold this Invoice",
                 topMargin: 25.h),
           ),
         ],
        );
    

    This is how I want my PopupMenuButton to be appear

    enter image description here

    • ambiguous58
      ambiguous58 about 3 years
      Have you looked into CustomPaint?
    • Majid Ali
      Majid Ali about 3 years
      Yes I have, I have created triangle through CustomPaint but do not know how to wrap in around PopupMenuButton container , I wrapped it once around PopupMenuButton but triangle is being added on PopupMenu option button which is right in appbar which I do not want , I want to add triangle around PopupMenuButton container as shown in above picture
  • Majid Ali
    Majid Ali about 3 years
    Thanks a lot indeed it was so kind of you
  • Sangeetha Sakthivel
    Sangeetha Sakthivel over 2 years
    @rrickimaru thank you so much!. I have a doubt what we need to do when we want the clip in the left side instead or fright ?
  • rickimaru
    rickimaru over 2 years
    @SangeethaSakthivel Just play on the values of path in TooltipShape::getOuterPath(...).