Flutter桌面端-窗口适配经验分享

前言

以目前的情况来看,Flutter的桌面端软件其实跟移动端软件很像,因为Flutter桌面端目前默认只有一个窗口,而不是像原生的桌面端软件一样,经常会有很多个窗口。

比较不一样的是,移动端是直接全屏显示,桌面端的软件是以窗口的形式存在的。

而桌面端窗口大小可以设置,还可以由用户自由放大缩小。

所以一般桌面端软件都需要对窗口做一些配置,比如设置启动时的默认窗口大小以达到最佳的界面显示,设置最小的窗口大小来避免界面变形严重或者遮盖了重要界面等等。

另外某些应用还会有关闭前确认,监听窗口活跃情况,自定义窗口标题栏之类的需求。

插件选择

像这种窗口相关的需求,Flutter原生并没有提供比较好的支持。目前使用比较多的是两个插件,window_managerbitsdojo_window

这两个库的功能差不多,基本的窗口设置都有,而且都支持MacOSWindowsLinux系统。而且大部分情况下只需要在dart层处理,用起来还算简单。

我最后选择的是window_manager

一是bitsdojo_window这个库感觉维护不太上心,几个月才维护一次,而window_manager维护要勤快得多。

二是window_manager是国内的learnFlutter开源组织开发维护的,有比较好的中文文档,而且这种不相伯仲的情况,果断支持下国内的大佬。

实践分享

window_manager有较完善的中文文档,具体可查看 README-ZH.md

我主要是分享项目中用到的一些功能。

基本窗口设置

如下面的代码的所示,window_manager通过配置WindowOptions可以设置默认窗口大小,最小窗口大小,设置窗口居中显示,设置窗口的标题等。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
 
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
 
  // 必须加上这一行。
  await windowManager.ensureInitialized();
  WindowOptions windowOptions = const WindowOptions(
    size: Size(600, 400), // 设置默认窗口大小
    minimumSize: Size(300, 220), // 设置最小窗口大小
    center: true, // 设置窗口居中
    title: "window_manager测试Demo", // 设置窗口标题
  );
  windowManager.waitUntilReadyToShow(windowOptions, () async {
    await windowManager.show();
    await windowManager.focus();
  });
 
  runApp(const MyApp());
}

如下图一是启动后默认的窗口大小,图二是最小的缩放窗口。当然默认是可以缩放到屏幕大小的,还可以最小化,不赘述。

窗口状态监听

通过注册监听器可以监听Windows的各种状态。我们可以在回调里面做一些自己的事情。

dart 复制代码
class _MyHomePageState extends State<MyHomePage> with WindowListener {
  @override
  void initState() {
    super.initState();
    // 注册windowManager监听器
    windowManager.addListener(this);
  }
 
  @override
  void dispose() {
    // 移除windowManager监听器
    windowManager.removeListener(this);
    super.dispose();
  }
 
  // === WindowListener回调 ===
 
  // 窗口准备关闭时触发
  @override
  void onWindowClose() {
    // 窗口关闭前做一些操作。
    // 我是关闭了adb服务。否则adb服务会一直在运行。
    debugPrint("onWindowClose");
    super.onWindowClose();
  }
 
  // 窗口获得焦点时触发(比如去浏览器看文章后回来点击本App的窗口)
  @override
  void onWindowFocus() {
    // 获得焦点时做一些处理。我是用于记录记录用户操作,方便后续查找问题及统计活跃情况。
    debugPrint("onWindowFocus");
    super.onWindowFocus();
  }
 
  // 窗口失去焦点时触发(比如去浏览器看文章了,焦点就不在本App了)
  @override
  void onWindowBlur() {
    // 失去焦点时做一些处理。我是用于记录记录用户操作,方便后续查找问题及统计活跃情况。
    debugPrint("onWindowBlur");
    super.onWindowBlur();
  }
 
  // === WindowListener回调 ===
}

设置应用高度占满屏幕

我做的另外的一个桌面应用,界面基本上是跟移动端一致的。而且首页是一个列表,所以想要尽量让启动后应用的高度占满屏幕。

这个需求一开始打算使用window_manager插件来实现,但是发现达不到想要的效果。

后面发现learnFlutter还有一个开源库是screen_retriever ,这个插件允许 Flutter 桌面 应用检索关于屏幕大小,显示,光标位置等信息。

试了下确实可以获取到屏幕的高度,所以实现方式是使用screen_retriever获取到屏幕的高度之后再使用window_manager 设置窗口大小。

dart 复制代码
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
 
  // 必须加上这一行。
  await windowManager.ensureInitialized();
 
  // 获取屏幕可用大小
  Display primaryDisplay = await screenRetriever.getPrimaryDisplay();
  // 获取屏幕可用高度
  var windowHeight = primaryDisplay.visibleSize?.height ?? 820;
 
  WindowOptions windowOptions = WindowOptions(
    // size: Size(600, 400), // 设置默认窗口大小
    size: Size(600, windowHeight), // 设置默认窗口大小
    minimumSize: const Size(300, 220), // 设置最小窗口大小
    center: true, // 设置窗口居中
    title: "window_manager测试Demo", // 设置窗口标题
  );
  windowManager.waitUntilReadyToShow(windowOptions, () async {
    await windowManager.show();
    await windowManager.focus();
  });
 
  runApp(const MyApp());
}

参考

本文Demo
window_manager bitsdojo_window screen_retriever
learnFlutter
Flutter - 桌面应用窗口化实战

相关推荐
行星飞行7 分钟前
从 cursor 、 Claude code 迁移到 codex,30 分钟快速上手 codex 常用技巧
前端
Pu_Nine_918 分钟前
前端埋点从入门到企业实践:手写一个Demo + 主流方案对比
前端·埋点
ZC跨境爬虫25 分钟前
跟着 MDN 学 HTML day_56:(HTML 表格基础完全指南)
前端·javascript·ui·html·音视频
Dxy123931021630 分钟前
CSS滤镜使用方法完全指南
前端·css
AC赳赳老秦41 分钟前
OpenClaw与WPS宏联动:批量执行WPS复杂操作,解决办公表格批量处理难题
java·前端·数据库·自动化·需求分析·deepseek·openclaw
Larcher1 小时前
# 告别“古法编程”:吴恩达 AI 课程学习笔记与生日贺卡项目实战
前端·github·ai编程
用户852495071841 小时前
# 大二前端新人的AI初体验:跟着吴恩达学“Vibe Coding”,我如何用提示词“指挥”AI写代码?
前端
bupt_011 小时前
Hermes深入理解及源码解析(二):Hermes的记忆机制
java·服务器·前端
飘尘1 小时前
WebAssembly 是什么?它为什么重要?
前端·javascript
情绪总是阴雨天~1 小时前
大模型 Function Call(函数调用)详解:原理、实践与数据库智能查询 Agent
前端·数据库·人工智能