window_manager 现在构建在 nativeapi 之上, 它是 C++ 核心库 libnativeapi/nativeapi 的 Flutter 绑定, macOS、Windows、Linux 共用同一份实现。从 0.5.x 升级?请看从 0.5.x 升级。
问题反馈: 请统一到 nativeapi issues 提交问题和功能需求,并注明包名、版本、操作系统,附上最小复现示例。
这个插件让 Flutter 桌面应用可以调整、移动、显示、隐藏和装饰自己的窗口。
English | 简体中文
| Linux | macOS | Windows |
|---|---|---|
| ✔️ | ✔️ | ✔️ |
把它加到你的 pubspec.yaml 里:
dependencies:
window_manager: ^0.6.0或者
dependencies:
window_manager:
git:
url: https://github.com/leanflutter/window_manager.git
ref: main- Flutter 3.47 / Dart 3.13 及以上,macOS 10.15 及以上。
- Linux 构建机需要 GTK 3、X11 和 Xi 的开发文件:
sudo apt-get install libgtk-3-dev libx11-dev libxi-dev
import 'package:window_manager/window_manager.dart';
final window = WindowManager.instance.getCurrent()!;
window.title = 'window_manager';
window.setSize(const Size(1000, 700).toNative(), false);
window.minimumSize = const Size(640, 480).toNative();
window.center();
window.show();
// 本应用所有窗口的所有窗口事件。
WindowManager.instance.addListener((event) {
switch (event) {
case WindowFocusedEvent():
debugPrint('window ${event.windowId} focused');
case WindowResizedEvent():
debugPrint('window ${event.windowId} is now ${event.newSize.toSize()}');
default:
break;
}
});
// 无论用户怎样关闭,关闭这个窗口前先询问。关闭请求只会发给窗口自己的监听器。
window.addListener((event) async {
if (event is WindowCloseRequestedEvent && !await confirmClose()) {
event.request.cancel();
}
});Window 使用的是 nativeapi 的 Size、Point、Rectangle、Color,它们和 Flutter
的同名类型冲突,所以没有导出:用 toNative() 把 Flutter 的值转过去,用 toSize()、
toOffset()、toRect()、toColor() 转回来。
使用 Flutter 的多窗口 API 时,package:window_manager/windowing.dart 可以拿到每个 Flutter
窗口控制器背后的 Window:
import 'package:window_manager/windowing.dart';
final window = controller.nativeWindow; // 或者 nativeWindowOf(controller)
window?.title = 'Inspector';隐藏系统标题栏,改由 widget 来拖动和缩放:
final window = WindowManager.instance.getCurrent()!;
window.titleBarStyle = TitleBarStyle.hidden;
// 在应用里:
DragToResizeArea(
child: Column(
children: [
WindowCaption(
brightness: Theme.of(context).brightness,
title: const Text('window_manager'),
),
Expanded(child: body),
],
),
)本插件的示例应用演示的是 0.5.x 兼容 API。完整示例——同时管理多个窗口、 父子窗口、每一个原生属性——在 nativeapi 的 window_example。
为 window_manager 0.5.x 写的代码,只要把导入从
package:window_manager/window_manager.dart 换成
package:window_manager/legacy.dart 就能继续工作:老的 windowManager、
WindowListener、WindowOptions 和 calcWindowPosition 都在那里,底层换成了原生 API。
导入路径特意要改:legacy.dart 是一座桥,不是这个包的未来。里面的类都标了
@Deprecated,会在之后的版本里删掉——能迁就迁到上面的原生 API。
import 'package:window_manager/legacy.dart';
await windowManager.ensureInitialized();
await windowManager.waitUntilReadyToShow(
const WindowOptions(size: Size(1000, 700), center: true),
() async {
await windowManager.show();
await windowManager.focus();
},
);和 0.5.x 的差别:
- 需要 Flutter 3.47 / Dart 3.13 和 macOS 10.15(0.5.x 是 Flutter 3.3、macOS 10.11),
但不再需要在
MainFlutterWindow.swift、my_application.cc或 Windows runner 里做插件 自己的接入——已经没有任何平台插件代码了。 close()、destroy()、setPreventClose()的行为和以前一样:设了setPreventClose(true)之后,标题栏的关闭按钮和close()都会报告onWindowClose而不关闭窗口,destroy()仍然会关掉它。关闭最后一个窗口时是否退出应用,由平台的 runner 决定。 未开启preventClose时也会报告onWindowClose。destroy()跳过兼容层的回调和否决, 其他原生监听器仍可取消关闭请求。onWindowResized、onWindowMoved和onWindowResize、onWindowMove一起到达: nativeapi 每次变化只报一个事件,没有"过程中"和"结束时"之分。- Windows 的
isDockable、isDocked、dock、undock通过系统 appbar 预留桌面工作区, 并触发onWindowDocked/onWindowUndocked。取消停靠恢复原来的窗口尺寸和位置, 原生窗口销毁时释放预留空间。这个功能独立于 Windows 的贴靠布局。 grabKeyboard()/ungrabKeyboard()在 Linux X11 上独占和释放键盘;Wayland 和其他平台 返回 false。窗口隐藏或销毁时释放独占。popUpWindowMenu()在 Windows 和提供系统菜单的 Linux 窗口管理器上会在光标处弹出系统菜单, 在 macOS 上什么都不做。setIgnoreMouseEvents的forward在平台支持时(macOS、Windows、X11)保留鼠标悬停事件; 其他平台上窗口直接忽略鼠标,不转发。- Windows 支持
maximize(vertically: true),双击上下调整大小边缘会切换垂直最大化。 macOS 支持setPosition/setBounds的animate,以及setVisibleOnAllWorkspaces的visibleOnFullScreen。不支持原生窗口动画的平台直接应用几何变化。 windowButtonVisibility也控制 Windows 和 Linux 的原生标题栏按钮,隐藏/显示整组按钮时 保留各按钮的独立策略。Windows 上setClosable(false)只禁用关闭命令,保留其他按钮; Linux 服务端装饰是否响应取决于窗口管理器。- Linux 保留首次显示前的全屏、最小化请求,并支持取消;退出启动全屏后恢复请求的普通窗口宽度。
getId()保持 macOS 窗口服务器编号和 WindowsHWND的旧语义。原生 API 的查询和事件 使用window.id;平台互操作使用 macOS 的window.nativeNumber或 Windows 的window.nativeObject。setAsFrameless()通过window.setFrameless(true)去除边框。显式设置任一标题栏样式都会恢复边框。 macOS 兼容层保留旧版的透明背景和阴影默认值;原生无边框策略独立保留阴影偏好。- macOS 的
setMaximizable(false)拒绝原生 zoom,不再连带禁用边缘缩放。 setAlignment支持任意Alignment,不再只认那九个常量。WindowCaption的关闭按钮会关闭窗口,并先经过窗口的关闭监听器,所以setPreventClose对它同样有效。在 Windows 11 上,它的最大化按钮会弹出贴靠布局。- Windows 全屏时仍忽略
startDragging()、startResizing(),保持 0.5.x 行为;此限制和 原生窗口所属线程上的派发由 core 处理。 screen_retriever和path不再是依赖。- 新示例只用
package:flutter/widgets.dart;完整示例是 nativeapi 的 window_example。
0.5.x(legacy.dart) |
原生 API(window_manager.dart) |
|---|---|
windowManager(应用的那一个窗口) |
WindowManager.instance.getCurrent()——还有 get(id)、getAll()、getWindowAtPoint();每个窗口都是独立的 Window |
await windowManager.getSize()、setSize(size) |
window.size.toSize()、window.setSize(size.toNative(), animate)——同步,不需要 await |
getBounds() / setBounds(rect) |
window.bounds.toRect()、window.bounds = rect.toNative();不含装饰的区域用 window.contentBounds |
getPosition() / setPosition(offset) |
window.position.toOffset()、window.position = offset.toNative() |
setMinimumSize / setMaximumSize / setAspectRatio |
window.minimumSize、window.maximumSize、window.aspectRatio |
show() / show(inactive: true) / hide() |
window.show() / window.showInactive() / window.hide() |
focus()、blur()、isFocused() |
window.focus()、window.blur()、window.isFocused |
maximize()、unmaximize()、minimize()、restore() |
window 上的同名方法,不需要 await |
setFullScreen(bool) / isFullScreen() |
window.isFullScreen |
setResizable、setMovable、setMinimizable、setMaximizable、setClosable |
window.isResizable、isMovable、isMinimizable、isMaximizable、isClosable——还有 isFullScreenable |
setAlwaysOnTop / setAlwaysOnBottom |
window.isAlwaysOnTop / window.isAlwaysOnBottom |
setSkipTaskbar(true) |
window.isVisibleInTaskbar = false |
setTitle / getTitle |
window.title |
setAsFrameless() |
window.setFrameless(true),同时隐藏标题栏和原生按钮 |
getId() |
macOS 的 window.nativeNumber;Windows 的 window.nativeObject.address |
setTitleBarStyle(style, windowButtonVisibility:) |
window.titleBarStyle、window.isWindowControlButtonsVisible——还有 setTitleBarColors() |
setHasShadow、setOpacity、setBackgroundColor |
window.hasShadow、window.opacity、window.backgroundColor——还有 window.visualEffect |
setIgnoreMouseEvents(ignore, forward:) |
window.setIgnoreMouseEvents(ignore, forward) |
close() / destroy() |
window.close(),会先询问窗口的关闭监听器 |
setPreventClose(true) 配合 onWindowClose |
window.addListener((event) { if (event is WindowCloseRequestedEvent) event.request.cancel(); }) |
popUpWindowMenu() |
window.showSystemMenu(position)——用 Window.isSystemMenuSupported() 判断平台是否支持 |
setVisibleOnAllWorkspaces(bool) |
window.isVisibleOnAllWorkspaces |
visibleOnFullScreen: |
window.setVisibleOnFullScreen(bool)、window.isVisibleOnFullScreen |
setBounds(rect, animate: true) |
window.animateBounds(rect.toNative());返回 false 时直接设置 window.bounds |
maximize(vertically: true) |
window.setMaximizedVertically(true) / false、window.isMaximizedVertically |
dock(side:, width:)、undock()、isDocked() |
window.dock(WindowDockSide.left, width)、window.undock()、window.dockSide |
grabKeyboard()、ungrabKeyboard() |
window 上的同名方法;Window.isKeyboardGrabSupported() 查询当前显示服务是否支持 |
startDragging() / startResizing(edge) |
window 上的同名方法;DragToMoveArea、DragToResizeArea 已经替你调用了 |
setProgressBar、setBadgeLabel、setIcon、setBrightness |
Application.instance——它们属于应用,不属于某一个窗口 |
WindowListener |
单个窗口用 window.addListener((event) { switch (event) { case WindowFocusedEvent(): … } }),所有窗口用 WindowManager.instance.addListener——还有 WindowBlurredEvent、WindowMinimizedEvent、WindowMaximizedEvent、WindowRestoredEvent、WindowMovedEvent、WindowResizedEvent、WindowEnteredFullScreenEvent、WindowExitedFullScreenEvent、WindowCreatedEvent、WindowClosedEvent |
calcWindowPosition(size, alignment) |
DisplayManager.instance——getAll()、getPrimary()、getCursorPosition(),以及每个 Display 的 workArea |
waitUntilReadyToShow、ensureInitialized、getDevicePixelRatio
没有对应的原生 API:直接设好需要的属性,准备好了再调 window.show()。
- AuthPass - Password Manager based on Flutter for all platforms. Keepass 2.x (kdbx 3.x) compatible.
- Biyi (比译) - A convenient translation and dictionary app written in dart / Flutter.
- BlueBubbles - BlueBubbles is an ecosystem of apps bringing iMessage to Android, Windows, and Linux
- LunaSea - A self-hosted controller for mobile and macOS built using the Flutter framework.
- Linwood Butterfly - Open source note taking app written in Flutter
- RustDesk - Yet another remote desktop software, written in Rust. Works out of the box, no configuration required.
- Ubuntu Desktop Installer - This project is a modern implementation of the Ubuntu Desktop installer.
window_manager 现在直接重新导出 nativeapi 的窗口 API——Window、WindowManager、
TitleBarStyle、ResizeEdge、VisualEffect、各种窗口事件以及用于响应关闭请求的
EventRequest,还有 nativeapi_flutter 的 DragToMoveArea、DragToResizeArea、
MaximizeButtonArea 三个 widget 和类型转换——再加上它自己的 WindowCaption、
WindowCaptionButton 和 VirtualWindowFrame。只有还在用 0.5.x API 的代码才需要导入
package:window_manager/legacy.dart。