Flutter弹出菜单插件app_popup_menu的使用

Flutter弹出菜单插件app_popup_menu的使用

app_popup_menu 是一个增强版的Flutter弹出菜单插件,旨在提供更动态和适应性更强的菜单选项。本文将介绍如何安装和使用这个插件,并提供一个完整的示例demo。

安装

首先,在你的 pubspec.yaml 文件中添加 app_popup_menu 依赖:

dependencies:
  app_popup_menu: ^1.0.0

注意:始终使用主要版本号(如 1.0.0),这样可以自动获取次要版本中的新功能和补丁版本中的修复。

示例代码

以下是一个完整的示例demo,展示如何在Flutter应用中使用 app_popup_menu 插件。

main.dart

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BuildInheritedWidget(child: HomeScreen()),
    );
  }
}

class BuildInheritedWidget extends StatefulWidget {
  final Widget child;

  BuildInheritedWidget({required this.child});

  @override
  _BuildInheritedWidgetState createState() => _BuildInheritedWidgetState();
}

class _BuildInheritedWidgetState extends State<BuildInheritedWidget> {
  String data = '';

  @override
  Widget build(BuildContext context) {
    return InheritedData(
      data: data,
      child: widget.child,
    );
  }
}

class InheritedData extends InheritedWidget {
  final String data;

  InheritedData({required this.data, required Widget child})
      : super(child: child);

  static InheritedData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<InheritedData>();
  }

  @override
  bool updateShouldNotify(InheritedData oldWidget) {
    return data != oldWidget.data;
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late AppPopupMenu<String> appMenu01;
  late AppPopupMenu<int> appMenu02;
  late AppPopupMenu<String> appMenu03;

  @override
  void initState() {
    super.initState();

    appMenu01 = AppPopupMenu<String>(
      items: ['Option 1', 'Option 2', 'Option 3'],
      initialValue: 'Option 3',
      onSelected: (String value) {
        InheritedData.of(context)?.data = value;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('appMenu01 option: $value')),
        );
      },
      tooltip: "Here's a tip for you.",
      elevation: 8,
      icon: const Icon(Icons.settings),
      offset: const Offset(0, 45),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
    );

    appMenu02 = AppPopupMenu<int>(
      menuItems: const [
        PopupMenuItem(value: 1, child: Text('First')),
        PopupMenuItem(value: 2, child: Text('Second')),
      ],
      initialValue: 2,
      onSelected: (int value) {
        InheritedData.of(context)?.data = value.toString();
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('appMenu02 option: $value')),
        );
      },
      onCanceled: () {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('appMenu02: Nothing selected.')),
        );
      },
      tooltip: "Here's a tip for you.",
      elevation: 12,
      icon: const Icon(Icons.tablet),
      offset: const Offset(0, 65),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      color: Colors.deepOrangeAccent,
    );

    appMenu03 = AppPopupMenu<String>(
      items: ['One', 'Two', 'Three'],
      initialValue: 'Three',
      onSelected: (String value) {
        InheritedData.of(context)?.data = value;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('appMenu03 option: $value')),
        );
      },
      onCanceled: () {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('appMenu03: Nothing selected.')),
        );
      },
      tooltip: "Here's a tip for you.",
      elevation: 8,
      icon: const Icon(Icons.settings),
      offset: const Offset(0, 45),
      padding: const EdgeInsets.all(16),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Popup Menu Examples'),
        actions: [
          appMenu01,
          appMenu02,
          appMenu03.set(
            initialValue: 'Three',
            onCanceled: () {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('appMenu03: Nothing selected.')),
              );
            },
            tooltip: "Here's a tip for you.",
            elevation: 8,
            icon: const Icon(Icons.settings),
            offset: const Offset(0, 45),
            padding: const EdgeInsets.all(16),
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          ),
        ],
      ),
      body: const MenuOption(),
    );
  }
}

class MenuOption extends StatelessWidget {
  const MenuOption({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final data = InheritedData.of(context)?.data ?? '';
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            '$data',
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    );
  }
}

解释

  1. InheritedWidget: 使用 InheritedData 组件来传递数据给子组件。
  2. AppPopupMenu: 创建多个 AppPopupMenu 实例,分别设置不同的参数。
  3. onSelected 和 onCanceled: 当用户选择或取消选择菜单项时,显示相应的 SnackBar 提示信息。
  4. AppBar Actions: 在 AppBaractions 中添加 AppPopupMenu 实例。

通过上述步骤,你可以轻松地在Flutter应用中集成并使用 app_popup_menu 插件,创建更美观和动态的弹出菜单。希望这个示例对你有所帮助!


更多关于Flutter弹出菜单插件app_popup_menu的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter弹出菜单插件app_popup_menu的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用app_popup_menu插件来实现弹出菜单的示例代码。app_popup_menu是一个用于在Flutter应用中创建弹出菜单的插件。

首先,确保你已经在pubspec.yaml文件中添加了app_popup_menu依赖:

dependencies:
  flutter:
    sdk: flutter
  app_popup_menu: ^latest_version  # 替换为最新的版本号

然后,运行flutter pub get来安装依赖。

接下来是一个完整的示例,展示如何使用app_popup_menu

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Popup Menu Example'),
      ),
      body: Center(
        child: GestureDetector(
          onLongPress: () {
            showPopupMenu(
              context: context,
              builder: (BuildContext context) {
                return PopupMenu(
                  menuItems: [
                    PopupMenuItem(
                      value: 'Item 1',
                      child: Text('Item 1'),
                    ),
                    PopupMenuItem(
                      value: 'Item 2',
                      child: Text('Item 2'),
                    ),
                    PopupMenuItem(
                      value: 'Item 3',
                      child: Text('Item 3'),
                    ),
                  ],
                  onSelected: (String value) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                        content: Text('Selected: $value'),
                      ),
                    );
                  },
                );
              },
            );
          },
          child: Container(
            width: 200,
            height: 100,
            color: Colors.grey.withOpacity(0.5),
            child: Center(
              child: Text(
                'Long Press to Show Menu',
                style: TextStyle(fontSize: 24),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

// 这是一个自定义的 showPopupMenu 函数,因为 app_popup_menu 插件没有直接提供该函数。
// 你可以根据插件的 API 自行封装一个类似的函数,这里是一个简单的示例。
Future<void> showPopupMenu({
  required BuildContext context,
  required PopupMenuBuilder builder,
}) async {
  final overlay = Overlay.of(context)!;
  final relativeRect = RelativeRect.fromRect(
    Rect.fromPoints(
      context.findRenderObject()!.localToGlobal(Offset.zero),
      context.findRenderObject()!.localToGlobal(context.size!.bottomRight(Offset.zero)),
    ),
    Offset.zero & overlay!.size,
  );
  final _menu = builder(context);

  final _controller = OverlayEntry(
    builder: (context) => Positioned(
      width: _menu.preferredSize.width,
      height: _menu.preferredSize.height,
      left: relativeRect.left,
      top: relativeRect.top + context.findRenderObject()!.size.height,
      child: Material(
        elevation: 8.0,
        child: _menu,
      ),
    ),
  );

  overlay.insert(_controller);

  _controller.resultFuture.whenComplete(() => _controller.remove());

  // 你可以在这里添加逻辑来处理点击外部区域时关闭菜单
  // 例如使用 GestureDetector 监听点击事件,然后调用 _controller.remove()
}

// PopupMenu 和 PopupMenuItem 需要根据 app_popup_menu 插件的实际 API 来定义
// 以下是一个假设的 PopupMenu 和 PopupMenuItem 示例
class PopupMenu extends StatelessWidget {
  final List<PopupMenuItem> menuItems;
  final ValueChanged<dynamic> onSelected;

  PopupMenu({required this.menuItems, required this.onSelected});

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: menuItems.map((item) {
        return GestureDetector(
          onTap: () => onSelected(item.value),
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
            child: item.child,
          ),
        );
      }).toList(),
    );
  }

  Size get preferredSize => Size(double.infinity, menuItems.length * 56.0); // 假设每个菜单项的高度为 56
}

class PopupMenuItem {
  final dynamic value;
  final Widget child;

  PopupMenuItem({required this.value, required this.child});
}

typedef PopupMenuBuilder = Widget Function(BuildContext context);

注意

  1. app_popup_menu插件的实际API可能与上述示例中的PopupMenuPopupMenuItem有所不同。你需要查阅插件的官方文档或源代码以获取准确的用法。
  2. 上述代码中的showPopupMenu函数是一个自定义的示例,用于展示如何在Flutter中实现弹出菜单的功能。实际使用时,你可能需要根据app_popup_menu插件提供的API进行调整。
  3. 由于app_popup_menu插件的API可能会更新,建议查阅最新的插件文档或源代码以获取最新的用法。
回到顶部