You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter桌面系统托盘应用启动动画自定义实现方案问询

解决Flutter桌面托盘应用启动时直接常驻托盘的需求

针对你的系统托盘应用启动效果需求,核心思路是阻止主窗口初始显示,直接初始化托盘图标,而非通过动画隐藏已弹出的窗口(这也是普通UI动画插件无法解决的原因,因为框架默认会先创建并显示主窗口)。以下是跨平台的实现方案:

1. 依赖准备

添加桌面托盘和窗口管理的核心插件到pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  system_tray: ^2.0.0  # 跨平台系统托盘支持
  window_manager: ^0.3.0  # 窗口可见性、任务栏控制

2. 核心代码实现

在main.dart中控制窗口初始化逻辑,优先启动托盘而非主窗口:

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();
  const windowOptions = WindowOptions(
    visible: false,  // 启动阶段不显示主窗口
    skipTaskbar: true,  // 不在系统任务栏显示图标
    size: Size(400, 300),
  );
  
  windowManager.waitUntilReadyToShow(windowOptions, () async {
    await windowManager.hide(); // 确保窗口彻底隐藏
  });

  // 初始化系统托盘
  final systemTray = SystemTray();
  // 替换为你的托盘图标路径(需准备适配各平台的图标文件)
  await systemTray.initSystemTray(
    iconPath: 'assets/icons/tray_icon.png',
    toolTip: '你的托盘应用名称',
  );

  // 构建托盘右键菜单
  final menu = Menu();
  await menu.buildFrom([
    MenuItemLabel(
      label: '显示窗口',
      onClicked: (_) async {
        await windowManager.show();
        await windowManager.focus();
      },
    ),
    MenuItemLabel(
      label: '隐藏窗口',
      onClicked: (_) async => await windowManager.hide(),
    ),
    MenuItemSeparator(),
    MenuItemLabel(
      label: '退出',
      onClicked: (_) async {
        await systemTray.destroy();
        await windowManager.close();
      },
    ),
  ]);
  await systemTray.setContextMenu(menu);

  // 处理托盘左键点击:切换窗口显示/隐藏
  systemTray.registerSystemTrayEventHandler((event) {
    if (event == SystemTrayEvent.click) {
      windowManager.isVisible().then((visible) async {
        visible ? await windowManager.hide() : await windowManager.show();
      });
    }
  });

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '托盘应用',
      home: Scaffold(
        appBar: AppBar(title: const Text('主窗口')),
        body: const Center(child: Text('点击托盘图标控制窗口显示/隐藏')),
      ),
    );
  }
}

3. 平台专属配置

macOS

在macos/Runner/Info.plist中添加配置,将应用设为后台应用(Dock中不显示图标):

<key>LSUIElement</key>
<string>YES</string>

Windows

若需要彻底消除启动时的窗口痕迹,可修改windows/runner/main.cpp中的窗口显示逻辑:

// 找到CreateAndShowWindow函数,替换ShowWindow调用
ShowWindow(window, SW_HIDE); // 原代码为SW_SHOW

Linux

在应用的.desktop文件中添加NoDisplay=true,避免应用列表中显示该应用,同时确保窗口启动时隐藏。

关键说明

普通Flutter动画插件无法实现需求的原因是:框架默认会先创建并渲染主窗口,再执行UI动画。而我们需要的是从窗口初始化阶段就阻止显示,直接通过系统托盘作为唯一交互入口,因此必须借助窗口管理和系统托盘的底层API实现。

内容的提问来源于stack exchange,提问作者Sushma Shrestha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 00:20:45