Drawer:侧面导航栏

Drawer如何使用

是什么

Drawer 是一个从屏幕边缘滑出的侧边导航面板,常用于在应用中提供导航菜单、设置选项、用户资料等内容。

它通常和 Scaffold 搭配使用:

  • 放在 Scaffold.drawer(左侧抽屉)
  • Scaffold.endDrawer(右侧抽屉)

打开关闭方式

打开和关闭 Drawer 的方式

除了点击 AppBar 自动弹出外,也可以手动控制 Drawer 的打开关闭:

Scaffold.of(context).openDrawer();     // 打开左侧
Scaffold.of(context).openEndDrawer();  // 打开右侧
Navigator.pop(context);                // 关闭抽屉
Get.back();														// 关闭抽屉

注意:要在 BuildercontextScaffold 内部时才能调用 Scaffold.of(context)

Scaffold.drawer的默认行为

当你在 Scaffold 中提供了 drawer 时:

  • AppBar 会自动在左上角显示一个“汉堡菜单图标”(三条杠),叫做 DrawerButton
  • 点击它会自动调用 Scaffold.of(context).openDrawer() 打开左侧抽屉

这个图标只会出现在 drawer 有值而且 AppBar 没有自己指定 leading

常用属性

Drawer 本身的属性不多,主要用的是它的 child(通常是 ListView) 里放什么内容。

属性 类型 作用
child Widget Drawer 的内容主体
elevation double 阴影高度
backgroundColor Color 背景颜色
width double Drawer 的宽度
shape ShapeBorder Drawer 的外形边框(比如圆角)

常用的相关组件

组件 用途
Drawer 抽屉整体容器
DrawerHeader 抽屉顶部的标题区域(可放用户信息、头像)
ListView 容纳菜单项,支持滚动
ListTile 单个菜单项
UserAccountsDrawerHeader 一个带头像、用户名、邮箱等信息的专用头部

案例

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: MyDrawerDemo()));
}

class MyDrawerDemo extends StatelessWidget {
  const MyDrawerDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Drawer & EndDrawer 示例'),
        actions: [
          // AppBar 右上角按钮,用于打开右侧抽屉
          Builder(
            builder: (context) {
              return IconButton(
                icon: const Icon(Icons.settings),
                onPressed: () {
                  // 打开右侧抽屉
                  Scaffold.of(context).openEndDrawer();
                },
              );
            },
          ),
        ],
      ),

      // 左侧抽屉
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: [
            // UserAccountsDrawerHeader 显示用户信息
            const UserAccountsDrawerHeader(
              // 账户名称
              accountName: Text('张三'),
              // 账户邮箱
              accountEmail: Text('zhangsan@example.com'),
              // 头像
              currentAccountPicture: CircleAvatar(
                backgroundImage: AssetImage('assets/avatar.png'),
              ),
              // 头部背景
              decoration: BoxDecoration(color: Colors.blue),
            ),
            // 主页
            ListTile(
              leading: const Icon(Icons.home),
              title: const Text('主页'),
              onTap: () {
                Navigator.pop(context); // 关闭抽屉
              },
            ),
            ListTile(
              leading: const Icon(Icons.person),
              title: const Text('个人资料'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),

      // 右侧抽屉
      endDrawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: [
            // DrawerHeader 显示标题
            const DrawerHeader(
              decoration: BoxDecoration(color: Colors.green),
              child: Text('设置菜单', style: TextStyle(color: Colors.white)),
            ),
            // 深色模式开关
            SwitchListTile(
              value: true,
              onChanged: (v) {},
              title: const Text('深色模式'),
            ),
            // 退出登录
            ListTile(
              leading: const Icon(Icons.logout),
              title: const Text('退出登录'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),

      body: Center(
        child: Builder(
          builder: (context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    // 手动打开左侧抽屉
                    Scaffold.of(context).openDrawer();
                  },
                  child: const Text('打开左侧抽屉'),
                ),
                ElevatedButton(
                  onPressed: () {
                    // 手动打开右侧抽屉
                    Scaffold.of(context).openEndDrawer();
                  },
                  child: const Text('打开右侧抽屉'),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

AppBar的默认情况

automaticallyImplyLeading

在AppBar中有一个配置:

AppBar(
  automaticallyImplyLeading: true, // 默认就是 true
)

automaticallyImplyLeading: true 时,AppBar自动决定是否在左上角显示一个「leading」图标(通常是返回箭头或 Drawer 菜单图标)。

它会按以下优先级判断:

场景 默认显示的图标
drawerleading 为空 显示「三条杠」菜单图标 (DrawerButton)
有可返回的上一级路由 (Navigator.canPop) 且 leading 为空 显示返回箭头 (BackButton)
都没有 不显示任何图标

automaticallyImplyLeading: false时,就表示不要自动生成任何图标,哪怕当前页面可以返回、或有 drawer,也都不显示。

修改 drawer的默认图标

只要自己设置 AppBar.leading 属性,覆盖掉默认的 DrawerButton

AppBar 会自动在左上角显示一个“汉堡菜单图标”(三条杠),叫做 DrawerButton

点击它会自动调用 Scaffold.of(context).openDrawer() 打开左侧抽屉

appBar: AppBar(
  title: const Text('自定义 Drawer 图标'),
  leading: Builder(
    builder: (context) {
      return IconButton(
        icon: const Icon(Icons.menu_open), // ← 自定义图标
        onPressed: () {
          Scaffold.of(context).openDrawer(); // 手动打开 Drawer
        },
      );
    },
  ),
),

如果想完全隐藏左上角图标

appBar: AppBar(
  automaticallyImplyLeading: false,
)

×

喜欢就点赞,疼爱就打赏