Flutter如何自定义macOS的titlebar

在Flutter开发macOS应用时,如何自定义窗口的titlebar样式?目前默认的titlebar与设计风格不匹配,想实现以下功能:

  1. 隐藏系统默认的titlebar
  2. 添加自定义按钮(如最小化/关闭)
  3. 支持拖拽区域调整窗口位置
  4. 修改标题文字样式和颜色

是否有官方推荐方案或第三方插件可以实现?需要兼容最新的Flutter稳定版。

2 回复

在Flutter中自定义macOS标题栏,可使用window_manager插件。通过setTitleBarStyle方法设置透明或隐藏标题栏,然后使用自定义Widget模拟标题栏。需注意适配macOS系统版本。

更多关于Flutter如何自定义macOS的titlebar的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在 Flutter 中自定义 macOS 应用的 titlebar,可以通过以下步骤实现:

1. 启用 macOS 平台的自定义标题栏

macos/Runner/AppDelegate.swift 文件中,修改 applicationDidFinishLaunching 方法,启用无边框窗口并自定义标题栏。

import Cocoa
import FlutterMacOS

class AppDelegate: FlutterAppDelegate {
  override func applicationDidFinishLaunching(_ notification: Notification) {
    // 获取主窗口
    if let window = NSApplication.shared.windows.first {
      // 设置为无标题栏风格,以便自定义
      window.styleMask.insert(.fullSizeContentView)
      window.titlebarAppearsTransparent = true
      window.titleVisibility = .hidden
      
      // 可选:隐藏标准窗口按钮(关闭、最小化、最大化)
      // window.standardWindowButton(.closeButton)?.isHidden = true
      // window.standardWindowButton(.miniaturizeButton)?.isHidden = true
      // window.standardWindowButton(.zoomButton)?.isHidden = true
    }
    super.applicationDidFinishLaunching(notification)
  }
}

2. 在 Flutter 中构建自定义标题栏

在 Dart 代码中,使用 AppBar 或自定义 Widget 模拟标题栏,并处理拖拽功能。

import 'package:flutter/material.dart';

class CustomTitleBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50, // 设置标题栏高度
      color: Colors.blue, // 自定义背景色
      child: Row(
        children: [
          // 自定义标题
          Padding(
            padding: EdgeInsets.only(left: 16),
            child: Text(
              '自定义标题',
              style: TextStyle(color: Colors.white),
            ),
          ),
          Spacer(),
          // 自定义按钮(如关闭、最小化)
          WindowButtons(),
        ],
      ),
    );
  }
}

// 自定义窗口按钮(需通过 platform channel 调用原生方法)
class WindowButtons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        IconButton(
          icon: Icon(Icons.minimize, color: Colors.white),
          onPressed: () {
            // 调用原生方法最小化窗口
          },
        ),
        IconButton(
          icon: Icon(Icons.close, color: Colors.white),
          onPressed: () {
            // 调用原生方法关闭窗口
          },
        ),
      ],
    );
  }
}

3. 使用 platform channel 实现窗口控制

若需自定义按钮功能(如关闭、最小化),需通过 platform channel 调用 macOS 原生 API。

  • 在 Dart 中定义 channel:
import 'package:flutter/services.dart';

class WindowControl {
  static const platform = MethodChannel('window_control');

  static Future<void> minimizeWindow() async {
    try {
      await platform.invokeMethod('minimizeWindow');
    } on PlatformException catch (e) {
      print("Failed: '${e.message}'.");
    }
  }

  static Future<void> closeWindow() async {
    try {
      await platform.invokeMethod('closeWindow');
    } on PlatformException catch (e) {
      print("Failed: '${e.message}'.");
    }
  }
}
  • 在 macOS 中实现 channel 方法(在 AppDelegate.swift 中):
override func applicationDidFinishLaunching(_ notification: Notification) {
  // 其他设置...

  let controller = mainFlutterWindow?.contentViewController as? FlutterViewController
  let channel = FlutterMethodChannel(name: "window_control", binaryMessenger: controller!.engine.binaryMessenger)
  
  channel.setMethodCallHandler { call, result in
    switch call.method {
    case "minimizeWindow":
      NSApplication.shared.windows.first?.miniaturize(nil)
      result(nil)
    case "closeWindow":
      NSApplication.shared.windows.first?.close()
      result(nil)
    default:
      result(FlutterMethodNotImplemented)
    }
  }
  
  super.applicationDidFinishLaunching(notification)
}

4. 在 Flutter 界面中使用

将自定义标题栏置于 ScaffoldappBar 或直接放在页面顶部。

Scaffold(
  appBar: PreferredSize(
    preferredSize: Size.fromHeight(50),
    child: CustomTitleBar(),
  ),
  body: YourContent(),
);

注意事项:

  • 确保 macos/Runner.xcworkspace 配置正确,允许无边框窗口。
  • 自定义标题栏需处理拖拽移动窗口(默认透明标题栏支持拖拽)。
  • 测试窗口按钮功能在不同 macOS 版本下的兼容性。

通过以上步骤,即可在 Flutter 中实现自定义 macOS 标题栏。

回到顶部