我想在flutter中制作一个可重用的PopupMenuButton,所以我可以调用该小部件并动态分配PopupMenuItem。

这是我所做的,但是会引发框架错误。我在 flutter 方面比较陌生。

这是应该重用的类:

class PopupMenu {
  PopupMenu({@required this.title, @required this.onTap});

  final String title;
  final VoidCallback onTap;
}

class PopupmMenuButtonBuilder {
  setPopup(List<PopupMenu> popupItem) {
    return PopupMenuButton<String>(
      onSelected: (_) {
        popupItem.forEach((item) => item.onTap);
      },
      itemBuilder: (BuildContext context) {
        popupItem.forEach(
          (item) {
            return <PopupMenuItem<String>>[
              PopupMenuItem<String>(
                value: item.title,
                child: Text(
                  item.title,
                ),
              ),
            ];
          },
        );
      },
    );
  }
}

然后我这样调用小部件:
child: PopupmMenuButtonBuilder().setPopup([
              PopupMenu(title: 'Item 1', onTap: () => print('item 1 selected')),
              PopupMenu(title: 'Item 2', onTap: () => print('item 2 selected')),
            ]),

它显示了3点图标按钮,但是当我点击该图标时,它将引发此错误:
I/flutter ( 8509): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 8509): The following assertion was thrown while handling a gesture:
I/flutter ( 8509): 'package:flutter/src/material/popup_menu.dart': Failed assertion: line 723 pos 10: 'items != null &&
I/flutter ( 8509): items.isNotEmpty': is not true.
I/flutter ( 8509): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8509): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8509): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8509):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8509): When the exception was thrown, this was the stack:
I/flutter ( 8509): #2      showMenu (package:flutter/src/material/popup_menu.dart:723:10)
I/flutter ( 8509): #3      _PopupMenuButtonState.showButtonMenu (package:flutter/src/material/popup_menu.dart:898:5)
I/flutter ( 8509): #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:511:14)
I/flutter ( 8509): #5      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:566:30)
I/flutter ( 8509): #6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:166:24)
I/flutter ( 8509): #7      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:240:9)
I/flutter ( 8509): #8      TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:211:7)
I/flutter ( 8509): #9      GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
I/flutter ( 8509): #10     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:225:20)
I/flutter ( 8509): #11     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:199:22)
I/flutter ( 8509): #12     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter ( 8509): #13     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)I/flutter ( 8509): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)I/flutter ( 8509): #18     _invoke1 (dart:ui/hooks.dart:233:10)
I/flutter ( 8509): #19     _dispatchPointerDataPacket (dart:ui/hooks.dart:154:5)
I/flutter ( 8509): (elided 5 frames from class _AssertionError and package dart:async)
I/flutter ( 8509): Handler: onTap
I/flutter ( 8509): Recognizer:
I/flutter ( 8509):   TapGestureRecognizer#8968f(debugOwner: GestureDetector, state: ready, won arena, finalPosition:
I/flutter ( 8509):   Offset(339.0, 54.0), sent tap down)
I/flutter ( 8509): ════════════════════════════════════════════════════════════════════════════════════════════════════

最佳答案

您的itemBuilder需要返回一个List。它实际上不返回任何内容-请注意return如何位于forEach内部,因此它只是从lambda返回。通常,forEach有时应为be avoided。另外,PopupMenuButtonBuilder类是冗余的-可以用静态或顶级函数代替。

尚不清楚的另一件事是,为什么要为每个选择调用每个onTap。如您目前所知,它将调用每个回调!

试试这个:

class PopupMenu {
  PopupMenu({@required this.title, @required this.onTap});

  final String title;
  final VoidCallback onTap;

  static PopupMenuButton<String> createPopup(List<PopupMenu> popupItems) {
    return PopupMenuButton<String>(
      onSelected: (value) {
        popupItems.firstWhere((e) => e.title == value).onTap();
      },
      itemBuilder: (context) => popupItems
          .map((item) => PopupMenuItem<String>(
                value: item.title,
                child: Text(
                  item.title,
                ),
              ))
          .toList(),
    );
  }
}

10-06 08:03