Flutter macOS窗口管理工具插件macos_window_utils的使用

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

Flutter macOS窗口管理工具插件macos_window_utils的使用

macos_window_utils 是一个Flutter包,它提供了一组方法来修改macOS上Flutter应用程序的 NSWindow。通过这个包,你可以轻松地自定义应用程序窗口的外观和行为,包括标题栏、透明效果、阴影等。

功能特性

macos_window_utils 提供了以下功能:

  • 设置应用窗口的材质
  • 进入/退出全屏模式或(取消)缩放窗口
  • 标记窗口为“文档已编辑”
  • 设置代表的文件名和URL
  • 隐藏/显示窗口标题
  • 启用/禁用全尺寸内容视图
  • 显示/隐藏和启用/禁用窗口的交通灯按钮
  • 设置窗口的alpha值
  • 添加工具栏到窗口并设置其样式
  • 为窗口添加副标题
  • 让窗口忽略鼠标事件
  • 使窗口完全透明(无模糊效果)
  • 启用/禁用窗口的阴影
  • 添加、删除和修改视觉效果子视图的方法和小部件
  • 设置窗口级别以及在同一级别内重新排序窗口
  • 修改窗口的样式掩码
  • 抽象的 NSWindowDelegate 类,用于检测窗口大小调整、移动、暴露和最小化等事件
  • NSAppPresentationOptions 类,允许修改窗口的全屏演示选项
  • 获取和设置窗口标准按钮的位置(如关闭、最小化和缩放按钮)
  • 控制窗口是否可由用户关闭,以及编程方式关闭窗口的方法

此外,该包还附带了一个示例项目,通过直观的可搜索用户界面展示了插件的功能。

入门指南

安装

首先,通过以下命令安装该包:

flutter pub add macos_window_utils

然后,在Xcode中打开项目的 macos/Runner.xcworkspace 文件夹,按 ⇧ + ⌘ + O 搜索 Runner.xcodeproj

Info > Deployment Target 中将 macOS Deployment Target 设置为10.14.6或更高版本。接着,打开项目的 Podfile(如果它没有在Xcode中显示,可以在VS Code中找到),并将第一行的最低部署版本设置为10.14.6或更高:

platform :osx, '10.14.6'

如果你希望Flutter可以绘制整个窗口,包括标题栏,则可以通过以下Dart代码启用全尺寸内容视图:

WindowManipulator.makeTitlebarTransparent();
WindowManipulator.enableFullSizeContentView();

建议使用 TitlebarSafeArea 小部件包裹你的应用程序(或部分),以确保应用程序不会被窗口标题栏覆盖:

TitlebarSafeArea(
  child: YourApp(),
)

为了实现类似macOS的“壁纸着色”效果,你可以设置窗口材质为 NSVisualEffectViewMaterial.windowBackground,并用 TransparentMacOSSidebar 包裹侧边栏小部件:

TransparentMacOSSidebar(
  child: YourSidebarWidget(),
)

初始化插件

初始化插件如下:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await WindowManipulator.initialize();
  runApp(MyApp());
}

之后,调用 WindowManipulator 类中的任何方法来操作你的应用程序窗口。

使用 NSWindowDelegate

如果你想监听窗口事件,如窗口大小调整、移动、暴露和最小化,可以使用 NSWindowDelegate。首先确保在 WindowManipulator.initialize 调用中设置了 enableWindowDelegatetrue

await WindowManipulator.initialize(enableWindowDelegate: true);

创建一个继承自 NSWindowDelegate 的类,并重写相应的方法:

class _MyDelegate extends NSWindowDelegate {
  @override
  void windowDidEnterFullScreen() {
    print('The window has entered fullscreen mode.');
    
    super.windowDidEnterFullScreen();
  }
}

然后,通过 WindowManipulator.addNSWindowDelegate 方法添加委托实例:

final delegate = _MyDelegate();
final handle = WindowManipulator.addNSWindowDelegate(delegate);

你可以使用返回的 NSWindowDelegateHandle 来稍后移除此委托:

handle.removeFromHandler();

使用 NSAppPresentationOptions

例如,要自动隐藏全屏模式下的工具栏,可以这样做:

final options = NSAppPresentationOptions.from({
  NSAppPresentationOption.fullScreen,
  NSAppPresentationOption.autoHideToolbar,
  NSAppPresentationOption.autoHideMenuBar,
  NSAppPresentationOption.autoHideDock,
});

options.applyAsFullScreenPresentationOptions();

请注意,NSAppPresentationOptions 使用 NSWindow 的委托来更改窗口的全屏演示选项,因此需要在 WindowManipulator.initialize 调用中将 enableWindowDelegate 设置为 true 才能工作。

示例代码

以下是完整的示例代码,展示了如何使用 macos_window_utils 插件:

import 'package:flutter/cupertino.dart';
import 'package:macos_window_utils/macos_window_utils.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await WindowManipulator.initialize(enableWindowDelegate: true);
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  Brightness? _brightness;

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    _brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangePlatformBrightness() {
    if (mounted) {
      setState(() {
        _brightness =
            WidgetsBinding.instance.platformDispatcher.platformBrightness;
      });
    }

    super.didChangePlatformBrightness();
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      title: 'macos_window_utils demo',
      theme: CupertinoThemeData(
        barBackgroundColor: const Color.fromRGBO(0, 0, 0, 0.0),
        scaffoldBackgroundColor: const Color.fromRGBO(0, 0, 0, 0.0),
        textTheme: CupertinoTextThemeData(
          textStyle: TextStyle(
            fontSize: 14,
            color: _brightness == Brightness.dark
                ? const Color.fromRGBO(255, 255, 255, 1.0)
                : const Color.fromRGBO(0, 0, 0, 1.0),
          ),
        ),
      ),
      home: const DecoratedBox(
        decoration: BoxDecoration(
          color: Color.fromRGBO(0, 0, 0, 1.0),
          backgroundBlendMode: BlendMode.clear,
        ),
        child: MyHomePage(),
      ),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isSidebarOpen = false;

  @override
  Widget build(BuildContext context) {
    return TransparentSidebarAndContent(
      isOpen: _isSidebarOpen,
      width: 280.0,
      sidebarBuilder: () => const TitlebarSafeArea(
        child: SidebarContent(),
      ),
      child: TitlebarSafeArea(
        child: CupertinoPageScaffold(
          navigationBar: CupertinoNavigationBar(
            middle: const Text('macos_window_utils demo'),
            leading: CupertinoButton(
              padding: EdgeInsets.zero,
              child: UiElementColorBuilder(
                  uiElementColorContainerInstanceProvider:
                      OwnedUiElementColorContainerInstanceProvider(),
                  builder: (context, colorContainer) {
                    return Icon(
                      CupertinoIcons.sidebar_left,
                      color: colorContainer.controlAccentColor,
                    );
                  }),
              onPressed: () => setState(
                () {
                  _isSidebarOpen = !_isSidebarOpen;
                },
              ),
            ),
          ),
          child: DefaultTextStyle(
            style: CupertinoTheme.of(context).textTheme.textStyle,
            child: SafeArea(
              child: MainArea(
                setState: setState,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

以上是关于 macos_window_utils 插件的详细说明和使用示例。希望这些信息对你有所帮助!


更多关于Flutter macOS窗口管理工具插件macos_window_utils的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter macOS窗口管理工具插件macos_window_utils的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 macos_window_utils 插件来管理 Flutter macOS 窗口的示例代码。这个插件允许你进行如设置窗口标题、调整窗口大小、最小化、最大化、关闭窗口等操作。

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

dependencies:
  flutter:
    sdk: flutter
  macos_window_utils: ^最新版本号  # 请替换为实际发布的最新版本号

然后,在 macOS 平台上,你需要进行一些平台特定的设置和代码编写。以下是一个完整的示例,展示了如何使用 macos_window_utils 插件来管理 Flutter macOS 窗口。

main.dart

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('macos_window_utils Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () {
                  setWindowTitle('New Window Title');
                },
                child: Text('Set Window Title'),
              ),
              ElevatedButton(
                onPressed: () {
                  minimizeWindow();
                },
                child: Text('Minimize Window'),
              ),
              ElevatedButton(
                onPressed: () {
                  maximizeWindow();
                },
                child: Text('Maximize Window'),
              ),
              ElevatedButton(
                onPressed: () {
                  closeWindow();
                },
                child: Text('Close Window'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void setWindowTitle(String title) async {
    if (await MacosWindowUtils.isMacOS) {
      MacosWindowUtils.setWindowTitle(title);
    } else {
      print('This function is only available on macOS.');
    }
  }

  void minimizeWindow() async {
    if (await MacosWindowUtils.isMacOS) {
      MacosWindowUtils.minimizeWindow();
    } else {
      print('This function is only available on macOS.');
    }
  }

  void maximizeWindow() async {
    if (await MacosWindowUtils.isMacOS) {
      MacosWindowUtils.maximizeWindow();
    } else {
      print('This function is only available on macOS.');
    }
  }

  void closeWindow() async {
    if (await MacosWindowUtils.isMacOS) {
      MacosWindowUtils.closeWindow();
    } else {
      print('This function is only available on macOS.');
    }
  }
}

Info.plist 配置

在 macOS 项目中,你通常需要在 Info.plist 文件中进行一些配置,但 macos_window_utils 插件通常不需要特别的配置(除非有特别说明)。

注意事项

  1. 权限:确保你的 Flutter 项目已经正确配置了 macOS 平台支持。
  2. 插件版本:检查并更新 macos_window_utils 插件到最新版本,以确保所有功能都正常工作。
  3. 错误处理:在生产代码中,添加适当的错误处理逻辑以处理可能的异常情况。

这个示例展示了如何使用 macos_window_utils 插件来管理 Flutter macOS 窗口的基本功能。你可以根据实际需求进一步扩展这些功能。

回到顶部