文章目录
Ai加Flutter实现自定义标题栏(appBar)
在这篇博客中,笔者会讲诉为什么要实现自定义标题栏 ,标题栏都有些什么功能 ,然后结合AI简单实现自定义标题栏!
话不多说,我们直接开始吧!
基础需求与环境准备
这篇文档默认你的设备已经配置了flutter环境且自身具备了如下:
- 一定的
Dart语法基础 - 了解甚至熟悉其他桌面应用开发框架(比如:
Qt以及其他) - 一个
flutter空项目->flutter create --empty your_project_name - 想要学会
flutter的心
补充说明 :
安装flutter环境来这里
dart语法基础来这里
新手入门项目来这里
注意: 学习程度因人而异,如果满足的点越多,理论上学习效率越高!
笔者的环境:
- Linux :
64位fedora 43 gnome,桌面系统Wayland,内核版本Linux 6.17.9-300.fc43.x86_64 - Flutter :
Flutter 3.38.5 - Dart :
Dart 3.10.4 - DevTools :
2.51.1 - 大模型 : 通义千问网页版(
Qwen3-Coder模型)
为什么要自定义标题栏
我们可以参考常见的应用vscode、QQ、微信等这些在(Windows、Linux和macOS)都有较强的统一风格,这就是自定义标题栏的目的------统一风格
插一嘴 :其实自定义标题栏可以避免大量因标题栏样式不统一而导致的问题(比如:
gnome49的标题栏不支持暗色主题等)
怎么实现自定义标题栏
需求拆解
(第一性原理)------标题栏的构成
我们需要把这个看似复杂的问题简单化,实现自定义标题栏那我们就要知道标题栏 的构成:窗口图标 、窗口标题 、窗口按钮 (最小化、最大与还原、关闭)!见下图:

注意 :
gnome和macOS不支持窗口图标!
(类比思维)------AppBar的构成
事实窗口标题栏和flutter中的appBar是吻合的,见下图

(需求转换)------隐藏系统默认标题栏使用AppBar
既然我们已经知道AppBar的功能可以平替窗口标题栏,
那么我们直接隐藏默认的使用AppBar自定义一个不就好了?
自定义标题栏------AppBar
(需求拆解)------隐藏与appBar实现对应功能
关闭系统默认的标题栏
标题栏与AppBar以及功能映射关系
- 窗口图标 ->
leading-> 显示窗口图标 - 窗口标题 ->
title-> 显示窗口标题 - 窗口图标们 ->
actions-> 显示对应图标以及窗口的隐藏,放大复原,关闭
(window_manager)------安装与导入自定义标题栏插件
- 安装
window_manager
bash
# 终端执行如下:
flutter pub add window_manager
- 导入插件
dart
// 程序顶部添加如下
import 'package:window_manager/window_manager.dart';
(window_manager)------隐藏默认标题栏
- 替换程序入口代码块
dart
void main() {
runApp(const MyApp());
}
替换为
dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
WindowOptions windowOptions = WindowOptions(
titleBarStyle: TitleBarStyle.hidden,
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.focus();
});
runApp(const MainApp());
}
注意 : 确保你创建的是空项目
window_manager插件官网

借助window_manager与appBar实现自定义标题栏
- 替换脚手架里的内容
dart
body: Center(child: Text('Hello World!'))
dart
//替换为
appBar: AppBar(
leading: Icon(Icons.favorite),
title: Text("自定义标题栏"),
actions: [
IconButton(onPressed: () {}, icon: Icon(Icons.horizontal_rule)),
IconButton(onPressed: () {}, icon: Icon(Icons.crop_square)),
IconButton(onPressed: () {}, icon: Icon(Icons.close)),
],
),
显示效果

借助window_manager实现appBar窗口按钮功能
- 添加最小化窗口和关闭窗口
dart
// 替换为如下:
appBar: AppBar(
leading: Icon(Icons.favorite),
title: Text("自定义标题栏"),
actions: [
IconButton(
onPressed: () {
windowManager.minimize();
},
icon: Icon(Icons.horizontal_rule),
),
IconButton(onPressed: () {}, icon: Icon(Icons.crop_square)),
IconButton(
onPressed: () {
windowManager.close();
},
icon: Icon(Icons.close),
),
],
),
- 还原与最大化窗口
dart
// 将 StatelessWidget 转为StatefulWidget
// vscode 选中StatelessWidget 显示代码操作(ctrl.)StatefulWidget
// _MainAppState 初始化变量用于记录是否最大化
bool _isMaximized = false
替换appBar为如下:
dart
appBar: AppBar(
leading: Icon(Icons.favorite),
title: Text("自定义标题栏"),
actions: [
IconButton(
onPressed: () {
windowManager.minimize();
},
icon: Icon(Icons.horizontal_rule),
),
IconButton(
onPressed: () {
if (_isMaximized) {
windowManager.unmaximize();
setState(() {
_isMaximized = !_isMaximized;
});
} else {
windowManager.maximize();
setState(() {
_isMaximized = !_isMaximized;
});
}
},
icon: _isMaximized
? Icon(Icons.crop_free)
: Icon(Icons.crop_square),
),
IconButton(
onPressed: () {
windowManager.close();
},
icon: Icon(Icons.close),
),
],
),
显示效果 
借助window_manager实现拖动窗口
简单的办法 直接监听鼠标事件
dart
//AppBar里添加如下
flexibleSpace: Listener(
onPointerDown: (_) => windowManager.startDragging(),
child: Container(color: Colors.transparent),
),
光标带拖动效果 我的系统并不支持
dart
flexibleSpace: MouseRegion(
cursor: SystemMouseCursors.move,
child: Listener(
onPointerDown: (_) => windowManager.startDragging(),
child: Container(color: Colors.transparent),
),
),
显示效果

注意:
- 都是长按鼠标左键拖动窗口,右键鼠标 跟随光标移动
- 一定要在Container 中添加颜色为透明 不然无法移动
最终的代码
dart
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
WindowOptions windowOptions = WindowOptions(
titleBarStyle: TitleBarStyle.hidden,
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.focus();
});
runApp(const MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
bool _isMaximized = false;
void _toggleMaximize() {
if (_isMaximized) {
windowManager.unmaximize();
} else {
windowManager.maximize();
}
setState(() => _isMaximized = !_isMaximized);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.favorite),
title: Text('自定义标题栏'),
flexibleSpace: Listener(
onPointerDown: (event) => windowManager.startDragging(),
child: Container(color: Colors.transparent),
),
actions: [
IconButton(
icon: Icon(Icons.horizontal_rule),
onPressed: windowManager.minimize,
),
IconButton(
icon: Icon(_isMaximized ? Icons.crop_free : Icons.crop_square),
onPressed: _toggleMaximize,
),
IconButton(icon: Icon(Icons.close), onPressed: windowManager.close),
],
),
body: Center(child: Text('Hello, World!')),
),
);
}
}