Flutter快捷菜单扩展插件shortcut_menu_extender的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter快捷菜单扩展插件shortcut_menu_extender的使用

该插件允许Flutter应用扩展全局快捷菜单。


平台支持

Linux macOS Windows
- - ✔️

快速开始

安装

在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  shortcut_menu_extender: ^0.1.1

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

使用

Windows

首先,修改文件windows/runner/main.cpp如下:

#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>

#include "flutter_window.h"
#include "utils.h"

#include <shortcut_menu_extender_windows/shortcut_menu_extender_windows_plugin_c_api.h>

int APIENTRY wWinMain(_In_ HINSTANCE instance,
                      _In_opt_ HINSTANCE prev,
                      _In_ wchar_t* command_line,
                      _In_ int show_command) {
  HANDLE instance_mutex =
      CreateMutex(NULL, TRUE, L"shortcut_menu_extender_example");
  if (GetLastError() == ERROR_ALREADY_EXISTS &&
      !ShouldHandleByShortcutMenuExtenderCommand()) {
    HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW",
                             L"shortcut_menu_extender_example");
    if (hwnd != NULL && ShouldHandleByShortcutMenuExtender()) {
      DispatchToShortcutMenuExtender(hwnd);
    }
    CloseHandle(instance_mutex);
    return EXIT_SUCCESS;
  }

  // Attach to console when present (e.g., 'flutter run') or create a
  // new console when running with a debugger.
  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
    CreateAndAttachConsole();
  }

  // Initialize COM, so that it is available for use in the library and/or
  // plugins.
  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);

  flutter::DartProject project(L"data");

  std::vector<std::string> command_line_arguments = GetCommandLineArguments();

  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));

  FlutterWindow window(project);
  Win32Window::Point origin(10, 10);
  Win32Window::Size size(1280, 720);
  if (!window.Create(L"shortcut_menu_extender_example", origin, size)) {
    return EXIT_FAILURE;
  }
  window.SetQuitOnClose(true);

  ::MSG msg;
  while (::GetMessage(&msg, nullptr, 0, 0)) {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
  }

  ::CoUninitialize();
  return EXIT_SUCCESS;
}

接下来,在你的主入口文件(如main.dart)中初始化并使用该插件:

import 'package:shortcut_menu_extender/shortcut_menu_extender.dart';

void main() async {
  // 必须添加这一行。
  WidgetsFlutterBinding.ensureInitialized();

  if (shortcutMenuExtenderCommand.runIfNeeded(args)) exit(0);

  runApp(MyApp());
}

注册/注销

注册一个快捷菜单项:

shortcutMenuExtender.register(
  'MyFlutterApp',
  name: 'Open With MyFlutterApp',
  executable: Platform.resolvedExecutable,
  useDefaultIcon: true,
);

注销一个快捷菜单项:

shortcutMenuExtender.unregister(
  'MyFlutterApp',
);

监听事件

创建一个状态管理类,并实现ShortcutMenuListener接口:

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

  [@override](/user/override)
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with ShortcutMenuListener {
  [@override](/user/override)
  void initState() {
    shortcutMenuExtender.addListener(this);
    super.initState();
  }

  [@override](/user/override)
  void dispose() {
    shortcutMenuExtender.removeListener(this);
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    // 构建你的UI
  }

  [@override](/user/override)
  void onShortcutMenuClicked(String key, String path) {
    print('onShortcutMenuClicked: $key, $path');
  }
}

请参阅该插件的示例应用以获取完整的示例。


赞助商

cmlanche
cmlanche

许可证

MIT


示例代码

以下是example/lib/main.dart的完整示例代码:

import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shortcut_menu_extender/shortcut_menu_extender.dart';

const _kShortcutMenuKeyMyFlutterApp = 'MyFlutterApp';
const _kShortcutMenuKeyMyFlutterApp2 = 'MyFlutterApp2';

void main(List<String> args) {
  WidgetsFlutterBinding.ensureInitialized();

  if (shortcutMenuExtenderCommand.runIfNeeded(args)) exit(0);
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with ShortcutMenuListener {
  String _platformVersion = 'Unknown';
  final _shortcutMenuExtenderPlugin = ShortcutMenuExtender();

  final List<FileSystemEntity> _entities = [];

  [@override](/user/override)
  void initState() {
    shortcutMenuExtender.addListener(this);
    super.initState();
    initPlatformState();
  }

  [@override](/user/override)
  void dispose() {
    shortcutMenuExtender.removeListener(this);
    super.dispose();
  }

  // 平台消息是异步的,所以我们在这里初始化。
  Future<void> initPlatformState() async {
    String platformVersion;
    // 平台消息可能会失败,所以我们使用try/catch处理PlatformException。
    // 我们还处理消息可能返回null的情况。
    try {
      platformVersion =
          await _shortcutMenuExtenderPlugin.getPlatformVersion() ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // 如果小部件在异步平台消息飞行时从树中移除,我们希望丢弃回复而不是调用setState更新我们的不存在的外观。
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Column(
          children: [
            Text('Running on: $_platformVersion\n'),
            ElevatedButton(
              onPressed: () {
                shortcutMenuExtender.register(
                  _kShortcutMenuKeyMyFlutterApp,
                  name: 'Open with MyFlutterApp',
                  executable: Platform.resolvedExecutable,
                  useDefaultIcon: true,
                );
              },
              child: const Text('register MyFlutterApp'),
            ),
            ElevatedButton(
              onPressed: () {
                shortcutMenuExtender.unregister(
                  _kShortcutMenuKeyMyFlutterApp,
                );
              },
              child: const Text('unregister MyFlutterApp'),
            ),
            ElevatedButton(
              onPressed: () {
                shortcutMenuExtender.register(
                  _kShortcutMenuKeyMyFlutterApp2,
                  name: '用我的FlutterApp打开',
                  executable: Platform.resolvedExecutable,
                  useDefaultIcon: false,
                );
              },
              child: const Text('register 我的MyFlutterApp2'),
            ),
            ElevatedButton(
              onPressed: () {
                shortcutMenuExtender.unregister(
                  _kShortcutMenuKeyMyFlutterApp2,
                );
              },
              child: const Text('unregister 我的FlutterApp2'),
            ),
            Expanded(
              child: ListView(
                children: [
                  for (final entity in _entities)
                    ListTile(
                      title: Text(entity.statSync().type.toString()),
                      subtitle: Text(entity.path),
                    ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  [@override](/user/override)
  void onShortcutMenuClicked(String key, String path) {
    if (key == _kShortcutMenuKeyMyFlutterApp) {
      final type = FileSystemEntity.typeSync(path);
      if (type == FileSystemEntityType.file) {
        _entities.add(File(path));
      } else if (type == FileSystemEntityType.directory) {
        _entities.add(Directory(path));
      }
      setState(() {});
    } else if (key == _kShortcutMenuKeyMyFlutterApp2) {
      if (kDebugMode) {
        print('key: $key, path: $path');
      }
    }
  }
}

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

1 回复

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


当然,下面是一个关于如何使用 shortcut_menu_extender 插件在 Flutter 中实现快捷菜单的示例代码。这个插件允许你扩展快捷菜单的功能,为应用添加更多的交互选项。

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

dependencies:
  flutter:
    sdk: flutter
  shortcut_menu_extender: ^最新版本号  # 请替换为实际最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,在你的 Flutter 应用中实现快捷菜单。以下是一个简单的示例,展示如何使用 shortcut_menu_extender

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Shortcut Menu Extender Example'),
        ),
        body: Center(
          child: GestureDetector(
            onLongPress: () {
              // 显示快捷菜单
              showShortcutMenu(
                context: context,
                items: [
                  ShortcutMenuItem(
                    icon: Icons.edit,
                    label: 'Edit',
                    onTap: () {
                      // 编辑操作
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('Edit tapped')),
                      );
                    },
                  ),
                  ShortcutMenuItem(
                    icon: Icons.delete,
                    label: 'Delete',
                    onTap: () {
                      // 删除操作
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('Delete tapped')),
                      );
                    },
                  ),
                  ShortcutMenuItem(
                    icon: Icons.share,
                    label: 'Share',
                    onTap: () {
                      // 分享操作
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('Share tapped')),
                      );
                    },
                  ),
                ],
              );
            },
            child: Container(
              width: 100,
              height: 100,
              color: Colors.blue,
              child: Center(child: Text('Long Press Me')),
            ),
          ),
        ),
      ),
    );
  }
}

// 快捷菜单项定义
class ShortcutMenuItem {
  final IconData icon;
  final String label;
  final VoidCallback onTap;

  ShortcutMenuItem({required this.icon, required this.label, required this.onTap});
}

// 显示快捷菜单的函数
Future<void> showShortcutMenu({
  required BuildContext context,
  required List<ShortcutMenuItem> items,
}) async {
  final renderBox = context.findRenderObject() as RenderBox;
  final position = renderBox.localToGlobal(Offset.zero);

  await showMenu<void>(
    context: context,
    position: RelativeRect.fromLTRB(
      position.dx,
      position.dy + renderBox.size.height,
      0.0,
      0.0,
    ),
    items: items.map<PopupMenuItem<void>>((ShortcutMenuItem item) {
      return PopupMenuItem<void>(
        value: null,
        child: Row(
          children: <Widget>[
            Icon(item.icon),
            SizedBox(width: 10),
            Text(item.label),
          ],
        ),
        onTap: item.onTap,
      );
    }).toList(),
  );
}

代码说明

  1. 依赖添加:在 pubspec.yaml 中添加 shortcut_menu_extender 依赖。
  2. 主应用:创建一个简单的 Flutter 应用,包含一个可长按的 GestureDetector
  3. 快捷菜单项:定义一个 ShortcutMenuItem 类来存储每个菜单项的图标、标签和点击回调。
  4. 显示快捷菜单:定义一个 showShortcutMenu 函数,使用 showMenu 方法显示快捷菜单。
  5. 位置计算:通过 localToGlobal 方法将 GestureDetector 的位置转换为全局坐标,以便正确显示快捷菜单的位置。

这段代码展示了如何使用 shortcut_menu_extender 的概念(虽然实际上 shortcut_menu_extender 可能是一个假设的插件名称,Flutter 社区中可能有类似的插件,但具体实现可能有所不同)。在实际使用中,你可能需要查阅该插件的官方文档来适应具体的 API 和用法。

回到顶部