自定义菜单栏
在 winodws 和 macOS 当中,都会有默认的菜单栏样式,如果我们不喜欢这种样式,是否可以对其进行修改呢?答案是肯定的,现在我们就来看看在 Flutter 当中如何修改默认的菜单栏,对默认的菜单栏进行隐藏,实现一个我们喜欢的菜单栏样式与功能。
windows 当中默认的菜单栏样式如下图所示:
macOS 中菜单栏的默认样式:
隐藏默认的菜单栏,并实现自己的样式:
下面我们来看看如何实现自定义菜单栏的需求:主要是借用window_manager
这个依赖包进行实现,使用这个依赖包,我们可以方便的实现调整窗口的大小、对窗口进行定位等功能。
- 添加依赖包
flutter pub add window_manager
- 隐藏默认菜单栏,实现自定义菜单栏
class WindowAdapter {
static Future<void> setSize() async {
//判断是否为桌面端应用
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
//等待 windows manager 完成初始化
await windowManager.ensureInitialized();
//设置在桌面端展示窗口的大小、应用在桌面当中的定位、背景色等
WindowOptions windowOptions = const WindowOptions(
size: Size(920, 680),
minimumSize: Size(920, 690),
center: true,
backgroundColor: Colors.transparent,
skipTaskbar: false,
titleBarStyle: TitleBarStyle.hidden,
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
//隐藏默认的菜单栏
await windowManager.setTitleBarStyle(TitleBarStyle.hidden,
windowButtonVisibility: false);
await windowManager.show();
await windowManager.focus();
});
}
}
}
由于隐藏了默认的菜单栏,会导致无法对应用窗口进行拖拽、放大和缩小,所以在这里我们新增了两个组件:一拖拽组件、另一个放大、缩小、关闭按钮组件,并调用 window_manager 提供的API实现对窗口的操作。
- 拖拽组件:只要对另一个组件进行修饰,那么另外一个组件便可以获得拖拽功能
class DragToMoveArea extends StatelessWidget {
final Widget child;
const DragToMoveArea({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
if (Platform.isAndroid || Platform.isIOS) return child;
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanStart: (details) {
//调用 window_manager 的 API 实现拖拽功能
windowManager.startDragging();
},
child: child,
);
}
}
- 缩小、放大、关闭按钮组件:
class WindowButtons extends StatefulWidget {
final List<Widget>? actions;
const WindowButtons({super.key, this.actions});
@override
State<WindowButtons> createState() => _WindowButtonsState();
}
class _WindowButtonsState extends State<WindowButtons> {
@override
Widget build(BuildContext context) {
Brightness brightness = Theme.of(context).brightness;
return Align(
alignment: Alignment.topRight,
child: Wrap(
spacing: 5,
children: [
if (widget.actions != null) ...widget.actions!,
SizedBox(
width: 30,
height: 30,
child: WindowCaptionButton.minimize(
brightness: brightness,
onPressed: () async {
bool isMinimized = await windowManager.isMinimized();
if (isMinimized) {
windowManager.restore();
} else {
windowManager.minimize();
}
},
),
),
SizedBox(
width: 30,
height: 30,
child: FutureBuilder<bool>(
future: windowManager.isMaximized(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return WindowCaptionButton.unmaximize(
brightness: brightness,
onPressed: () async {
await windowManager.unmaximize();
setState(() {});
},
);
}
return WindowCaptionButton.maximize(
brightness: brightness,
onPressed: () async {
await windowManager.maximize();
setState(() {});
},
);
},
),
),
SizedBox(
height: 30,
width: 30,
child: WindowCaptionButton.close(
brightness: brightness,
onPressed: () {
windowManager.close();
},
),
),
],
),
);
}
}
- 使用组件,在 AppBar 当中进行使用,就可以让其获得菜单栏的默认功能:
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(30),
child: DragToMoveArea(
child: AppBar(
actions: const [WindowButtons()],
),
)),