Ai加Flutter实现自定义标题栏(appBar)

文章目录

Ai加Flutter实现自定义标题栏(appBar)

在这篇博客中,笔者会讲诉为什么要实现自定义标题栏标题栏都有些什么功能 ,然后结合AI简单实现自定义标题栏

话不多说,我们直接开始吧!

基础需求与环境准备

这篇文档默认你的设备已经配置了flutter环境且自身具备了如下:

  • 一定的Dart语法基础
  • 了解甚至熟悉其他桌面应用开发框架(比如:Qt以及其他)
  • 一个flutter空项目-> flutter create --empty your_project_name
  • 想要学会flutter的心

补充说明
安装flutter环境来这里
dart语法基础来这里
新手入门项目来这里

注意: 学习程度因人而异,如果满足的点越多,理论上学习效率越高!

笔者的环境:

  • Linux : 64fedora 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模型)

为什么要自定义标题栏

我们可以参考常见的应用vscodeQQ微信等这些在(WindowsLinuxmacOS)都有较强的统一风格,这就是自定义标题栏的目的------统一风格

插一嘴 :其实自定义标题栏可以避免大量因标题栏样式不统一而导致的问题(比如:gnome49的标题栏不支持暗色主题等)

怎么实现自定义标题栏

需求拆解

(第一性原理)------标题栏的构成

我们需要把这个看似复杂的问题简单化,实现自定义标题栏那我们就要知道标题栏 的构成:窗口图标窗口标题窗口按钮 (最小化、最大与还原、关闭)!见下图:

注意 : gnomemacOS不支持窗口图标!

(类比思维)------AppBar的构成

事实窗口标题栏和flutter中的appBar是吻合的,见下图

(需求转换)------隐藏系统默认标题栏使用AppBar

既然我们已经知道AppBar的功能可以平替窗口标题栏,

那么我们直接隐藏默认的使用AppBar自定义一个不就好了?

自定义标题栏------AppBar

(需求拆解)------隐藏与appBar实现对应功能

关闭系统默认的标题栏

标题栏与AppBar以及功能映射关系

  • 窗口图标 -> leading-> 显示窗口图标
  • 窗口标题 ->title-> 显示窗口标题
  • 窗口图标们 -> actions -> 显示对应图标以及窗口的隐藏,放大复原,关闭
(window_manager)------安装与导入自定义标题栏插件
  1. 安装window_manager
bash 复制代码
# 终端执行如下:
flutter pub add window_manager
  1. 导入插件
dart 复制代码
// 程序顶部添加如下
import 'package:window_manager/window_manager.dart';
(window_manager)------隐藏默认标题栏
  1. 替换程序入口代码块
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实现自定义标题栏
  1. 替换脚手架里的内容
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窗口按钮功能
  1. 添加最小化窗口和关闭窗口
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),
            ),
          ],
        ),
  1. 还原与最大化窗口
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!')),
      ),
    );
  }
}

AI询问过程

通义AI对话过程

相关推荐
巴拉巴拉~~8 小时前
Flutter 通用图片预览组件 CommonImagePreview:缩放+滑动+保存+多图切换
flutter
巴拉巴拉~~8 小时前
Flutter 通用底部导航组件 CommonBottomNavWidget:状态保持 + 凸起按钮适配
flutter
走在路上的菜鸟8 小时前
Android学Dart学习笔记第二十节 类-枚举
android·笔记·学习·flutter
巴拉巴拉~~9 小时前
Flutter 通用表单输入组件 CustomInputWidget:校验 + 样式 + 交互一键适配
javascript·flutter·交互
yoona10209 小时前
Flutter 声明式 UI:为什么 build 会被反复调用?
flutter·ui·区块链·dex
ujainu小9 小时前
Flutter动画提效实战:animations 2.1.1 官方包全解析,4种Material动画开箱即用
flutter·animations
巴拉巴拉~~9 小时前
深入探索Flutter自定义绘制:从零到一实现炫酷仪表盘
flutter·ui
ujainu小9 小时前
Flutter 结合 path_provider 2.1.5 实现跨平台文件路径管理
flutter·path_provider
ujainu小9 小时前
Flutter image_picker 1.2.1 插件:图片与视频选择全攻略
flutter