Flutter Windows桌面端如何实现托盘单击/双击打开/隐藏应用 已按要求输出标题

我在用Flutter开发Windows桌面应用时,想实现系统托盘功能,但遇到一些问题:如何监听托盘图标的单击和双击事件?单击时希望隐藏应用窗口,双击时重新显示窗口。目前尝试了tray_managersystem_tray插件,但都没找到直接支持双击事件的方法。请问有没有成熟的解决方案?或者需要自己编写MethodChannel与原生代码交互?最好能提供具体实现示例。

2 回复

Flutter桌面端可通过system_tray插件实现托盘功能。监听单击/双击事件,调用show()/hide()控制窗口显隐。需注意平台差异,Windows需处理窗口最小化逻辑。

更多关于Flutter Windows桌面端如何实现托盘单击/双击打开/隐藏应用 已按要求输出标题的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


Flutter Windows桌面端实现托盘单击/双击打开/隐藏应用

实现方案

在Flutter Windows桌面端实现托盘功能需要使用system_traywindow_manager插件。

步骤

1. 添加依赖

dependencies:
  system_tray: ^2.0.0
  window_manager: ^0.3.0

2. 完整实现代码

import 'package:flutter/material.dart';
import 'package:system_tray/system_tray.dart';
import 'package:window_manager/window_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化窗口管理器
  await windowManager.ensureInitialized();
  
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WindowListener {
  final SystemTray _systemTray = SystemTray();
  final AppWindow _appWindow = AppWindow();
  
  bool _isWindowVisible = true;
  
  @override
  void initState() {
    super.initState();
    _initSystemTray();
    windowManager.addListener(this);
  }
  
  Future<void> _initSystemTray() async {
    // 初始化系统托盘
    await _systemTray.initSystemTray(
      title: "My App",
      iconPath: "assets/app_icon.ico", // 托盘图标路径
    );
    
    // 创建托盘菜单
    final Menu menu = Menu();
    await menu.buildFrom([
      MenuItemLabel(
        label: '显示/隐藏',
        onClicked: _toggleWindowVisibility,
      ),
      MenuSeparator(),
      MenuItemLabel(
        label: '退出',
        onClicked: _exitApp,
      ),
    ]);
    
    await _systemTray.setContextMenu(menu);
    
    // 设置托盘点击事件
    _systemTray.registerSystemTrayEventHandler((eventName) {
      if (eventName == kSystemTrayEventClick) {
        // 单击事件
        _toggleWindowVisibility();
      } else if (eventName == kSystemTrayEventDoubleClick) {
        // 双击事件
        _toggleWindowVisibility();
      }
    });
  }
  
  void _toggleWindowVisibility() async {
    if (_isWindowVisible) {
      // 隐藏窗口
      await windowManager.hide();
      setState(() {
        _isWindowVisible = false;
      });
    } else {
      // 显示窗口
      await windowManager.show();
      await windowManager.focus();
      setState(() {
        _isWindowVisible = true;
      });
    }
  }
  
  void _exitApp() {
    _appWindow.close();
  }
  
  @override
  void onWindowClose() async {
    // 点击关闭按钮时最小化到托盘而不是退出
    bool isPreventClose = await windowManager.isPreventClose();
    if (isPreventClose) {
      await windowManager.hide();
      setState(() {
        _isWindowVisible = false;
      });
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('托盘示例应用'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('应用主窗口'),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _toggleWindowVisibility,
                child: Text(_isWindowVisible ? '隐藏到托盘' : '显示窗口'),
              ),
            ],
          ),
        ),
      ),
    );
  }
  
  @override
  void dispose() {
    windowManager.removeListener(this);
    super.dispose();
  }
}

3. 配置说明

windows/runner/main.cpp中设置窗口关闭行为:

// 在窗口创建后添加
window->SetOnCloseRequested([&](winrt::Microsoft::UI::Xaml::Window const&, winrt::Microsoft::UI::Xaml::WindowCloseRequestedEventArgs const& args) {
    args.Handled(true); // 阻止默认关闭行为
    // 发送消息到Flutter端处理隐藏逻辑
    return;
});

功能特点

  • 单击托盘图标:切换窗口显示/隐藏
  • 双击托盘图标:切换窗口显示/隐藏
  • 右键菜单:提供显示/隐藏和退出选项
  • 关闭按钮:点击时隐藏到托盘而非退出

注意事项

  1. 需要准备合适的ICO格式图标文件
  2. 在Windows平台需要相应的权限配置
  3. 建议测试不同Windows版本的兼容性

这样就实现了完整的托盘单击/双击打开/隐藏应用功能。

回到顶部