Flutter中PopupMenuButton的自定义形状

问题描述

我想在Flutter中改变我的PopupMenuButton的形状,想在顶部添加一个三角形,如下图所示,我在谷歌上花了很多时间但没有成就请帮助我我是Flutter的新手所以我不知道如何更改这个认容器,现在它只有白色圆形容器,没有在它上面添加白色箭头/三角形。请帮忙,提前致谢

 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",text: "Hold this Invoice",topMargin: 25.h),],);

这就是我希望我的 PopupMenuButton 出现的方式

enter image description here

解决方法

您可以为自定义 PopupMenuButton 创建形状。

示例...

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,10,0);
    path.lineTo(rrect.width - 30,0);
    path.lineTo(rrect.width - 20,-10);
    path.lineTo(rrect.width - 10,0);
    path.quadraticBezierTo(rrect.width,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 - 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,);
}
,

试试这个:

class PopMenu extends StatefulWidget {
  @override
  _PopMenuState createState() => _PopMenuState();
}

class _PopMenuState extends State<PopMenu> {
  List<Icon> icons = [
    Icon(Icons.person),Icon(Icons.settings),Icon(Icons.credit_card),];
  GlobalKey _key = LabeledGlobalKey("button_icon");
  OverlayEntry _overlayEntry;
  Offset _buttonPosition;
  bool _isMenuOpen = false;

  void _findButton() {
    RenderBox renderBox = _key.currentContext.findRenderObject();
    _buttonPosition = renderBox.localToGlobal(Offset.zero);
  }

  void _openMenu() {
    _findButton();
    _overlayEntry = _overlayEntryBuilder();
    Overlay.of(context).insert(_overlayEntry);
    _isMenuOpen = !_isMenuOpen;
  }

  void _closeMenu() {
    _overlayEntry.remove();
    _isMenuOpen = !_isMenuOpen;
  }

  OverlayEntry _overlayEntryBuilder() {
    return OverlayEntry(
      builder: (context) {
        return Positioned(
          top: _buttonPosition.dy + 50,left: _buttonPosition.dx - 250,width: 300,child: _popMenu(),);
      },);
  }

  Widget _popMenu() {
    return Column(
      children: [
        Align(
          alignment: Alignment.centerRight,child: Padding(
            padding: EdgeInsets.only(right: 20),child: ClipPath(
              clipper: ArrowClipper(),child: Container(
                width: 17,height: 17,color: Color(0xFFF67C0B9),Container(
          width: 300,height: 300,decoration: BoxDecoration(
            color: Color(0xFFF67C0B9),borderRadius: BorderRadius.circular(4),child: Theme(
            data: ThemeData(
              iconTheme: IconThemeData(
                color: Colors.white,child: Column(
              mainAxisSize: MainAxisSize.min,children: List.generate(
                icons.length,(index) {
                  return GestureDetector(
                    onTap: () {},child: Container(
                      width: 300,height: 100,child: icons[index],);
                },);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          key: _key,decoration: BoxDecoration(
            color: Color(0xFFF5C6373),child: IconButton(
            icon: Icon(Icons.menu),color: Colors.white,onPressed: () {
              _isMenuOpen ? _closeMenu() : _openMenu();
            },);
  }
}

class ArrowClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path = Path();
    path.moveTo(0,size.height);
    path.lineTo(size.width / 2,size.height / 2);
    path.lineTo(size.width,size.height);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...