【问题标题】:Custom shape of PopupMenuButton in flutter扑动中PopupMenuButton的自定义形状
【发布时间】:2021-07-12 18:16:11
【问题描述】:

我想在flutter中改变我的PopupMenuButton的形状,想在顶部添加一个三角形,如下图所示,我在google上花了很多时间但没有成就请帮助我我是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",
         child: popUpMenuSingleItem(
             icon: AppAssets.DeliveryIcon,
             text: "Hold this Invoice",
             topMargin: 25.h),
       ),
     ],
    );

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

【问题讨论】:

  • 你看过CustomPaint吗?
  • 是的,我有,我通过 CustomPaint 创建了三角形,但不知道如何包裹在 PopupMenuButton 容器周围,我将它包裹在 PopupMenuButton 周围一次,但是在 appbar 中的 PopupMenu 选项按钮上添加了三角形我不想要,我想在 PopupMenuButton 容器周围添加三角形,如上图所示

标签: flutter customization shapes triangle popupmenubutton


【解决方案1】:

试试这个:

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),
            borderRadius: BorderRadius.circular(4),
          ),
          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;
  }
}

【讨论】:

    【解决方案2】:

    您可以为您的自定义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, 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,
          );
    }
    

    【讨论】:

    • 非常感谢,你真是太好了
    • @rrickimaru 非常感谢!我怀疑当我们想要左侧的剪辑而不是惊吓时我们需要做什么?
    • @SangeethaSakthivel 在TooltipShape::getOuterPath(...) 中使用path 的值。
    猜你喜欢
    • 2012-09-06
    • 2020-11-10
    • 1970-01-01
    • 2020-07-03
    • 2017-08-22
    • 2020-04-12
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多