页面:Scaffold

  1. 脚手架
  2. Scaffold 的主要作用
  3. Scaffold 常用参数
    1. drawerDragStartBehavior
  4. 代码示例

脚手架

定义:一种用来快速生成项目、模块或页面基本骨架的工具或组件,省去重复写模板代码的过程。它可以是:

  • 命令行工具(例如:vue create my-app 会生成一个 Vue 项目骨架)
  • 代码框架类(例如:Flutter 的 Scaffold 帮你生成页面基础布局)
  • 自动化生成器(例如:Django 的 startapp 会帮你生成 MVC 目录结构)

为什么叫做脚手架:

  • 在建筑里,脚手架本身不是房子的一部分,但它提供了施工的支撑,让工人能安全高效地完成工作。
  • 在软件里,脚手架代码本身可能不是业务核心,但它提供了开发的基础结构,让开发者能更快地进入业务逻辑编写。

常见软件脚手架例子:

场景 脚手架示例 作用
前端 create-react-app / vue-cli 生成项目目录、配置文件、入口文件
后端 django-admin startproject 创建 MVC 结构、配置数据库连接
Flutter Scaffold 提供 AppBar、body、drawer 等页面布局骨架
Node.js express-generator 自动生成路由、视图、静态文件结构

在 Flutter 里,Scaffold 叫做“页面布局脚手架”,意思是它帮你:

  • 先搭好一个页面的标准结构(AppBar、body、Drawer、BottomNavigationBar、FAB…)
  • 你只需要往这些位置放内容(Widget)就行,不必自己手写布局来摆放顶部、底部等

Scaffold对应 ios 的是 CupertinoPageScaffold

Scaffold 的主要作用

提供 Material 风格的基础布局结构

内置多个常用布局槽位(AppBar、Body、Drawer、BottomNavigationBar…)

统一管理 Material 特性(如 SnackBarBottomSheet 的显示)

Scaffold 常用参数

参数 作用 示例
appBar 顶部应用栏 AppBar(title: Text('标题'))
body 主体内容区域 Center(child: Text('内容'))
drawer 左侧抽屉菜单 Drawer(child: ListView(...))
endDrawer 右侧抽屉菜单 Drawer(...)
bottomNavigationBar 底部导航栏 BottomNavigationBar(items: [...])
floatingActionButton 悬浮按钮 FloatingActionButton(...)
backgroundColor 页面背景色 Colors.white
bottomSheet 底部固定面板 BottomSheet(...)
persistentFooterButtons 固定在底部的按钮组 [TextButton(...), TextButton(...)]
const Scaffold({
    Key key,
    // 菜单栏
    this.appBar,
    // 中间主体内容部分
    this.body,
    // 悬浮按钮
    this.floatingActionButton,
    // 悬浮按钮位置
    this.floatingActionButtonLocation,
    // 悬浮按钮动画
    this.floatingActionButtonAnimator,
    // 固定在下方显示的按钮
    this.persistentFooterButtons,
    // 左侧 侧滑抽屉菜单
    this.drawer,
    // 右侧 侧滑抽屉菜单
    this.endDrawer,
    // 底部菜单
    this.bottomNavigationBar,
    // 底部拉出菜单
    this.bottomSheet,
    // 背景色
    this.backgroundColor,
    // 自动适应底部padding
    this.resizeToAvoidBottomPadding,
    // 重新计算body布局空间大小,避免被遮挡
    this.resizeToAvoidBottomInset,
    // 是否显示到底部,默认为true将显示到顶部状态栏
    this.primary = true,
  	// 用来控制侧边抽屉(Drawer)滑动手势的响应方式。
    this.drawerDragStartBehavior = DragStartBehavior.down,
  })

drawerDragStartBehavior

drawerDragStartBehaviorScaffold 的一个可选参数,用来控制侧边抽屉(Drawer)滑动手势响应方式。它的类型是 DragStartBehavior 枚举,取值有:

  • DragStartBehavior.start
  • DragStartBehavior.down

在 Flutter 中,Drawer 可以通过手势(从屏幕边缘滑动)拉出来。手势事件的触发有两种时机:

  • DragStartBehavior.start(默认值):只有当手指真正滑动(有位移)时才触发拖动逻辑。也就是说,触摸屏幕不动,不会立刻触发拖动。
  • DragStartBehavior.down: 只要手指按下(down)就立即开始拖动逻辑,不等滑动位移。适合需要快速响应拖动的场景。
模式 行为
start 按下屏幕后必须有滑动位移,拖动才开始(更自然,防止误触)
down 按下的瞬间就进入拖动状态(响应更快,但可能会误触)

大多数情况下用默认的 start 就好,避免用户只是点一下屏幕边缘时就意外拉出抽屉。

代码示例

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

// 下面这段注释了的代码是一个 Cupertino 风格的页面示例,
// class CupertinoPage extends StatelessWidget {
//   const CupertinoPage({Key? key}) : super(key: key);

//   @override
//   Widget build(BuildContext context) {
//     return const CupertinoPageScaffold(
//       navigationBar: CupertinoNavigationBar(
//         middle: Text('我是标题'),
//       ),
//       child: Center(
//         child: Text('我是内容'),
//       ),
//     );
//   }
// }

void main() {
  runApp(const ScaffoldPage());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        // 菜单栏
        appBar: AppBar(title: const Text('菜单栏')),

        // 悬浮按钮
        floatingActionButton: FloatingActionButton(
          onPressed: () {},
          child: const Icon(Icons.add_photo_alternate),
        ),

        // 悬浮按钮位置
        floatingActionButtonLocation: FloatingActionButtonLocation.centerTop,

        // 固定在下方显示的按钮
        persistentFooterButtons: const [
          Text('固定在下方显示的按钮1'),
          Text('固定在下方显示的按钮2'),
        ],

        // 压缩顶部菜单空间
        primary: true,

        // 左侧 侧滑抽屉菜单
        drawer: const Drawer(child: Text('data')),

        // 右侧 侧滑抽屉菜单
        endDrawer: const Drawer(child: Text('data')),

        // 检测手势行为方式,与drawer配合使用 down 方式有卡顿,可以 start 方式
        drawerDragStartBehavior: DragStartBehavior.start,

        // 底部导航栏
        bottomNavigationBar: const Text('底部导航栏'),

        // 底部拉出菜单
        bottomSheet: const Text('底部拉出菜单'),

        // 背景色
        backgroundColor: Colors.amberAccent,

        // 自动适应底部padding
        resizeToAvoidBottomInset: true,

        // 正文:
        // Builder 是一个特殊的 Widget,用来创建一个新的 BuildContext。
        // 这么做的原因:Scaffold.of(context) 在 Flutter 里是用来获取离当前 context 最近的 ScaffoldState 实例的。
        // 换句话说:找到当前 Widget 树里最靠近它的 Scaffold,然后你就可以用这个 Scaffold 的方法(比如 openDrawer()、showSnackBar())来操作页面。
        // 如果直接用外部的 context,可能找不到最近的 Scaffold,会报错。
        // 所以这里用 Builder 创建了一个位于 Scaffold 内部的新 context,让 Scaffold.of(context) 能找到 Scaffold。
        body: Builder(
          builder: (BuildContext context) {
            return Center(
              child: ElevatedButton(
                onPressed: () {
                  // 脚手架管理
                  // 从当前 context 向上查找最近的 Scaffold,获取它的状态对象 ScaffoldState。
                  // 调用 openDrawer() 方法,手动打开 Scaffold 的 drawer(左侧抽屉菜单)。
                  // 这是一个页面结构操作。
                  Scaffold.of(context).openDrawer();

                  // 应用消息管理
                  // ScaffoldMessenger 是 Flutter 用来管理 SnackBar 的组件(比旧的 Scaffold.of(context).showSnackBar() 更灵活)。
                  // 它会从当前 context 找到最近的 ScaffoldMessenger,然后显示一个 SnackBar
                  // SnackBar 是一个底部弹出的提示条,这里显示 "Hello!",会在 2 秒后自动消失。
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('Hello!'),
                      duration: Duration(seconds: 2),
                    ),
                  );
                },
                child: const Text('应用消息管理'),
              ),
            );
          },
        ),
      ),
    );
  }
}

×

喜欢就点赞,疼爱就打赏