Scaffold
一个实现了基本Material Design视觉布局结构的组件
Scaffold提供了展示抽屉和底部的功能。通过Scaffold.of获取当前BuildContext的ScaffoldState,并使用ScaffoldState.showBottomSheet函数,可以展示底部抽屉,。
Scaffold布局,键盘以及刘海区域的显示
Scaffold将扩展以填充可用空间。这意味着它将占据整个窗口。当键盘出现的时候,Scaffold的祖先组件MediaQuery的MediaQueryData.viewInsets值会改变,此时Scaffold会被重建。默认情况下,Scaffold会调整大小腾出空间给键盘。如果不想Scaffold调整大小,可以将resizeToAvoidBottomInset设置为false。在任何情况下,如果有焦点组件在可滚动容器内,它将被滚动到视图中。
MediaQueryData.padding值定义了可能不会完全显示的区域,比如iphone上的刘海。通常情况下,Scaffold的body区域因为AppBar或者BottomNavigationBar可以避免碰触到这些不显示的区域,但是如果想要完全避免这种情况发生,可以使用SafeArea组件。
设置可拖动可滚动底部抽屉时同时设置悬浮按钮
如果Scaffold.bottomSheet是一个可拖动且可滚动的底部抽屉且同时设置了Scaffold.floatingActionButton。当底部抽屉拖动超过Scaffold高度的70%时,两件事将会发生:
Scaffold将会展示遮罩Scaffold.floatingActionButton将会以Curves.easeIn动画缩小,并且将会在底部抽屉完全盖住Scaffold时完全消失
一旦拖动底部抽屉覆盖小于高度的70%,那么遮罩将会消失且Scaffold.floatingActionButton将会恢复正常大小。
例子
例子1
import 'package:flutter/material.dart';
/// Flutter code sample for [Scaffold].
void main() => runApp(const ScaffoldExampleApp());
class ScaffoldExampleApp extends StatelessWidget {
const ScaffoldExampleApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(home: ScaffoldExample());
}
}
class ScaffoldExample extends StatefulWidget {
const ScaffoldExample({super.key});
State<ScaffoldExample> createState() => _ScaffoldExampleState();
}
class _ScaffoldExampleState extends State<ScaffoldExample> {
int _count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample Code')),
body: Center(child: Text('You have pressed the button $_count times.')),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
tooltip: 'Increment Counter',
child: const Icon(Icons.add),
),
);
}
}

例子2
import 'package:flutter/material.dart';
/// Flutter code sample for [Scaffold].
void main() => runApp(const ScaffoldExampleApp());
class ScaffoldExampleApp extends StatelessWidget {
const ScaffoldExampleApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(home: ScaffoldExample());
}
}
class ScaffoldExample extends StatefulWidget {
const ScaffoldExample({super.key});
State<ScaffoldExample> createState() => _ScaffoldExampleState();
}
class _ScaffoldExampleState extends State<ScaffoldExample> {
int _count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample Code')),
body: Center(child: Text('You have pressed the button $_count times.')),
backgroundColor: Colors.blueGrey.shade200,
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
tooltip: 'Increment Counter',
child: const Icon(Icons.add),
),
);
}
}

例子3
import 'package:flutter/material.dart';
/// Flutter code sample for [Scaffold].
void main() => runApp(const ScaffoldExampleApp());
class ScaffoldExampleApp extends StatelessWidget {
const ScaffoldExampleApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(home: ScaffoldExample());
}
}
class ScaffoldExample extends StatefulWidget {
const ScaffoldExample({super.key});
State<ScaffoldExample> createState() => _ScaffoldExampleState();
}
class _ScaffoldExampleState extends State<ScaffoldExample> {
int _count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample Code')),
body: Center(child: Text('You have pressed the button $_count times.')),
bottomNavigationBar: BottomAppBar(
shape: const CircularNotchedRectangle(),
child: Container(height: 50.0),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() {
_count++;
}),
tooltip: 'Increment Counter',
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}

构造函数
Scaffold.new({
Key? key,
PreferredSizeWidget? appBar,
Widget? body,
Widget? floatingActionButton,
FloatingActionButtonLocation? floatingActionButtonLocation,
FloatingActionButtonAnimator? floatingActionButtonAnimator,
List<Widget>? persistentFooterButtons,
AlignmentDirectional persistentFooterAlignment = AlignmentDirectional.centerEnd,
BoxDecoration? persistentFooterDecoration,
Widget? drawer,
DrawerCallback? onDrawerChanged,
Widget? endDrawer,
DrawerCallback? onEndDrawerChanged,
Widget? bottomNavigationBar,
Widget? bottomSheet,
Color? backgroundColor,
bool? resizeToAvoidBottomInset,
bool primary = true,
DragStartBehavior drawerDragStartBehavior = DragStartBehavior.start,
bool extendBody = false,
bool drawerBarrierDismissible = true,
bool extendBodyBehindAppBar = false,
Color? drawerScrimColor,
Widget? bottomSheetScrimBuilder(BuildContext, Animation<double>) = _defaultBottomSheetScrimBuilder,
double? drawerEdgeDragWidth,
bool drawerEnableOpenDragGesture = true,
bool endDrawerEnableOpenDragGesture = true,
String? restorationId
})
属性
| 属性名 | 类型 | 解释 |
|---|---|---|
| appBar | PreferredSizeWidget? | 顶部的AppBar |
| backgroundColor | Color? | Scaffold背景色 |
| body | Widget? | Scaffold中间的主体组件 |
| bottomNavigationBar | Widget? | Scaffold底部导航栏 |
| bottomSheet | Widget? | Scaffold底部抽屉 |
| bottomSheetScrimBuilder | Widget? Function(BuildContext, Animation<double>) | 一个builder函数用于创建底部抽屉的遮罩 |
| drawer | Widget? | 从body侧面滑出的一个面板抽屉,默认从左往右滑出 |
| drawerBarrierDismissible | bool | 是否可以通过点击遮罩关闭抽屉 |
| drawerDragStartBehavior | DragStartBehavior | 设置何时才判定为抽屉滑动,down用户触摸到屏幕即开始算,start用户触摸到屏幕并拖动一段距离开始算 |
| drawerEdgeDragWidth | double? | 从屏幕边缘拖动多少距离打开抽屉,如果设置为0,那么将禁用从屏幕边缘滑动打开抽屉的功能 |
| drawerEnableOpenDragGesture | bool | 设置是否允许从屏幕边缘滑动打开抽屉的功能 |
| drawerScrimColor | Color? | 抽屉遮罩颜色 |
| endDrawer | Widget? | 从body侧面滑出的一个面板抽屉,默认从右往左滑出 |
| endDrawerEnableOpenDragGesture | bool | 同上 |
| extendBody | bool | 设置body内容是否延伸到底部导航栏下面,通常用于将导航栏设置为透明或者毛玻璃风格 |
| extendBodyBehindAppBar | bool | 设置body内容是否延伸到AppBar下面,通常用于将导航栏设置为透明或者毛玻璃风格 |
| floatingActionButton | Widget? | 在body右下角展示的一个悬浮按钮 |
| floatingActionButtonLocation | FloatingActionButtonLocation? | 设置悬浮按钮展示位置 |
| floatingActionButtonAnimator | FloatingActionButtonAnimator? | 设置悬浮按钮移动到新位置的动画 |
| onDrawerChanged | DrawerCallback? | 当Scaffold.drawer打开或关闭时,调用该回调函数 |
| onEndDrawerChanged | DrawerCallback? | 当Scaffold.endDrawer打开或关闭时,调用该回调函数 |
| persistentFooterAlignment | AlignmentDirectional | 设置底部按钮的排列方式 |
| persistentFooterButtons | List<Widget>? | 设置底部按钮 |
| persistentFooterDecoration | BoxDecoration? | 设置包含底部按钮的Container的装饰样式 |
| primary | bool | 设置这个Scaffold是否在屏幕最顶层展示 |
| resizeToAvoidBottomInset | bool? | 设置为false时,弹出键盘时,Scaffold.body不会调整大小来腾出空间给键盘 |
| restorationId | String? | 用于保存和恢复 Scaffold 状态的恢复 ID |
静态方法
| 函数名 | 类型 | 解释 |
|---|---|---|
| geometryOf | (BuildContext context) -> ValueListenable<ScaffoldGeometry> | 返回给定上下文中最近的Scaffold祖先的ScaffoldGeometry的ValueListenable |
| hasDrawer | (BuildContext context, {bool registerForUpdates = true }) -> bool | 返回给定上下文最近的Scaffold是否有抽屉 |
| maybeOf | (BuildContext context) -> ScaffoldState? | 返回给定上下文最近的Scaffold的ScaffoldState, 可能为空 |
| of | (BuildContext context) -> ScaffoldState | 返回给定上下文最近的Scaffold的ScaffoldState |