脚手架
定义:一种用来快速生成项目、模块或页面基本骨架的工具或组件,省去重复写模板代码的过程。它可以是:
- 命令行工具(例如:
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
- https://api.flutter.dev/flutter/material/Scaffold-class.html
- https://api.flutter.dev/flutter/cupertino/CupertinoPageScaffold-class.html
Scaffold 的主要作用
提供 Material 风格的基础布局结构
内置多个常用布局槽位(AppBar、Body、Drawer、BottomNavigationBar…)
统一管理 Material 特性(如 SnackBar、BottomSheet 的显示)
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
drawerDragStartBehavior 是 Scaffold 的一个可选参数,用来控制侧边抽屉(Drawer)滑动手势的响应方式。它的类型是 DragStartBehavior 枚举,取值有:
DragStartBehavior.startDragStartBehavior.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('应用消息管理'),
),
);
},
),
),
);
}
}