showModalBottomSheet<T> function
- required BuildContext context,
- required WidgetBuilder builder,
- Color? backgroundColor,
- String? barrierLabel,
- double? elevation,
- ShapeBorder? shape,
- Clip? clipBehavior,
- BoxConstraints? constraints,
- Color? barrierColor,
- bool isScrollControlled = false,
- double scrollControlDisabledMaxHeightRatio = _kDefaultScrollControlDisabledMaxHeightRatio,
- bool isDismissible = true,
- bool enableDrag = true,
- bool? showDragHandle,
- bool useSafeArea = false,
- RouteSettings? routeSettings,
- AnimationController? transitionAnimationController,
- Offset? anchorPoint,
- AnimationStyle? sheetAnimationStyle,
- bool? requestFocus,
Shows a modal Material Design bottom sheet.
A modal bottom sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app.
A closely related widget is a persistent bottom sheet, which shows information that supplements the primary content of the app without preventing the user from interacting with the app. Persistent bottom sheets can be created and displayed with the showBottomSheet function or the ScaffoldState.showBottomSheet method.
The isScrollControlled parameter specifies whether this is a route for
a bottom sheet that will utilize DraggableScrollableSheet. Consider
setting this parameter to true if this bottom sheet has
a scrollable child, such as a ListView or a GridView,
to have the bottom sheet be draggable.
The isDismissible parameter specifies whether the bottom sheet will be
dismissed when user taps on the scrim.
The enableDrag parameter specifies whether the bottom sheet can be
dragged up and down and dismissed by swiping downwards.
The useSafeArea parameter specifies whether the sheet will avoid system
intrusions on the top, left, and right. If false, no SafeArea is added;
and MediaQuery.removePadding is applied to the top,
so that system intrusions at the top will not be avoided by a SafeArea
inside the bottom sheet either.
Defaults to false.
The optional backgroundColor, elevation, shape, clipBehavior,
constraints and transitionAnimationController
parameters can be passed in to customize the appearance and behavior of
modal bottom sheets (see the documentation for these on BottomSheet
for more details).
The transitionAnimationController controls the bottom sheet's entrance and
exit animations. It's up to the owner of the controller to call
AnimationController.dispose when the controller is no longer needed.
The optional settings parameter sets the RouteSettings of the modal bottom sheet
sheet. This is particularly useful in the case that a user wants to observe
PopupRoutes within a NavigatorObserver.
A DisplayFeature can split the screen into sub-screens. The closest one to
anchorPoint is used to render the content.
If no anchorPoint is provided, then Directionality is used:
- for TextDirection.ltr,
anchorPointisOffset.zero, which will cause the content to appear in the top-left sub-screen. - for TextDirection.rtl,
anchorPointisOffset(double.maxFinite, 0), which will cause the content to appear in the top-right sub-screen.
If no anchorPoint is provided, and there is no Directionality ancestor
widget in the tree, then the widget asserts during build in debug mode.
The context argument is used to look up the Navigator and Theme for
the bottom sheet. It is only used when the method is called. Its
corresponding widget can be safely removed from the tree before the bottom
sheet is closed.
The useRootNavigator parameter ensures that the root navigator is used to
display the BottomSheet when set to true. This is useful in the case
that a modal BottomSheet needs to be displayed above all other content
but the caller is inside another Navigator.
Returns a Future that resolves to the value (if any) that was passed to
Navigator.pop when the modal bottom sheet was closed.
The 'barrierLabel' parameter can be used to set a custom barrier label. Will default to MaterialLocalizations.modalBarrierDismissLabel of context if not set.
This example demonstrates how to use showModalBottomSheet to display a bottom sheet that obscures the content behind it when a user taps a button. It also demonstrates how to close the bottom sheet using the Navigator when a user taps on a button inside the bottom sheet.
To see it in action, copy and run this code snippet on DartPad.
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [showModalBottomSheet].
void main() => runApp(const BottomSheetApp());
class BottomSheetApp extends StatelessWidget {
const BottomSheetApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Bottom Sheet Sample')),
body: const BottomSheetExample(),
),
);
}
}
class BottomSheetExample extends StatelessWidget {
const BottomSheetExample({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: .center,
mainAxisSize: .min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
},
);
},
),
);
}
}
This sample shows the creation of showModalBottomSheet, as described in: https://m3.material.io/components/bottom-sheets/overview
To see it in action, copy and run this code snippet on DartPad.
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [showModalBottomSheet].
void main() => runApp(const BottomSheetApp());
class BottomSheetApp extends StatelessWidget {
const BottomSheetApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4)),
home: Scaffold(
appBar: AppBar(title: const Text('Bottom Sheet Sample')),
body: const BottomSheetExample(),
),
);
}
}
class BottomSheetExample extends StatelessWidget {
const BottomSheetExample({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 200,
child: Center(
child: Column(
mainAxisAlignment: .center,
mainAxisSize: .min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
},
);
},
),
);
}
}
The sheetAnimationStyle parameter is used to override the modal bottom sheet
animation duration and reverse animation duration.
The requestFocus parameter is used to specify whether the bottom sheet should
request focus when shown.
If requestFocus is not provided, the value of Navigator.requestFocus is
used instead.
If AnimationStyle.duration is provided, it will be used to override the modal bottom sheet animation duration in the underlying BottomSheet.createAnimationController.
If AnimationStyle.reverseDuration is provided, it will be used to override the modal bottom sheet reverse animation duration in the underlying BottomSheet.createAnimationController.
To disable the bottom sheet animation, use AnimationStyle.noAnimation.
This sample showcases how to override the showModalBottomSheet animation duration and reverse animation duration using AnimationStyle.
To see it in action, copy and run this code snippet on DartPad.
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [showModalBottomSheet].
void main() => runApp(const ModalBottomSheetApp());
class ModalBottomSheetApp extends StatelessWidget {
const ModalBottomSheetApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Modal Bottom Sheet Sample')),
body: const ModalBottomSheetExample(),
),
);
}
}
enum AnimationStyles { defaultStyle, custom, none }
const List<(AnimationStyles, String)> animationStyleSegments =
<(AnimationStyles, String)>[
(AnimationStyles.defaultStyle, 'Default'),
(AnimationStyles.custom, 'Custom'),
(AnimationStyles.none, 'None'),
];
class ModalBottomSheetExample extends StatefulWidget {
const ModalBottomSheetExample({super.key});
@override
State<ModalBottomSheetExample> createState() =>
_ModalBottomSheetExampleState();
}
class _ModalBottomSheetExampleState extends State<ModalBottomSheetExample> {
Set<AnimationStyles> _animationStyleSelection = <AnimationStyles>{
AnimationStyles.defaultStyle,
};
AnimationStyle? _animationStyle;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: .center,
children: <Widget>[
SegmentedButton<AnimationStyles>(
selected: _animationStyleSelection,
onSelectionChanged: (Set<AnimationStyles> styles) {
setState(() {
_animationStyle = switch (styles.first) {
AnimationStyles.defaultStyle => null,
AnimationStyles.custom => const AnimationStyle(
duration: Duration(seconds: 3),
reverseDuration: Duration(seconds: 1),
),
AnimationStyles.none => AnimationStyle.noAnimation,
};
_animationStyleSelection = styles;
});
},
segments: animationStyleSegments
.map<ButtonSegment<AnimationStyles>>((
(AnimationStyles, String) shirt,
) {
return ButtonSegment<AnimationStyles>(
value: shirt.$1,
label: Text(shirt.$2),
);
})
.toList(),
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
sheetAnimationStyle: _animationStyle,
builder: (BuildContext context) {
return SizedBox.expand(
child: Center(
child: Column(
mainAxisAlignment: .center,
mainAxisSize: .min,
children: <Widget>[
const Text('Modal bottom sheet'),
ElevatedButton(
child: const Text('Close'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
},
);
},
),
],
),
);
}
}
See also:
- BottomSheet, which becomes the parent of the widget returned by the
function passed as the
builderargument to showModalBottomSheet. - showBottomSheet and ScaffoldState.showBottomSheet, for showing non-modal bottom sheets.
- DraggableScrollableSheet, creates a bottom sheet that grows and then becomes scrollable once it reaches its maximum size.
- DisplayFeatureSubScreen, which documents the specifics of how DisplayFeatures can split the screen into sub-screens.
- The Material 2 spec at m2.material.io/components/sheets-bottom.
- The Material 3 spec at m3.material.io/components/bottom-sheets/overview.
- AnimationStyle, which is used to override the modal bottom sheet animation duration and reverse animation duration.
Implementation
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/bottom_sheet/show_modal_bottom_sheet.0.dart#body}
///
/// </callout-box>
///
/// <callout-box>
///
/// This sample shows the creation of [showModalBottomSheet], as described in:
/// https://m3.material.io/components/bottom-sheets/overview
///
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/bottom_sheet/show_modal_bottom_sheet.1.dart#body}
///
/// </callout-box>
///
/// The [sheetAnimationStyle] parameter is used to override the modal bottom sheet
/// animation duration and reverse animation duration.
///
/// The [requestFocus] parameter is used to specify whether the bottom sheet should
/// request focus when shown.
/// {@macro flutter.widgets.navigator.Route.requestFocus}
///
/// If [AnimationStyle.duration] is provided, it will be used to override
/// the modal bottom sheet animation duration in the underlying
/// [BottomSheet.createAnimationController].
///
/// If [AnimationStyle.reverseDuration] is provided, it will be used to
/// override the modal bottom sheet reverse animation duration in the
/// underlying [BottomSheet.createAnimationController].
///
/// To disable the bottom sheet animation, use [AnimationStyle.noAnimation].
///
/// <callout-box>
///
/// This sample showcases how to override the [showModalBottomSheet] animation
/// duration and reverse animation duration using [AnimationStyle].
///
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/bottom_sheet/show_modal_bottom_sheet.2.dart#body}
///
/// </callout-box>
///
/// See also:
///
/// * [BottomSheet], which becomes the parent of the widget returned by the
/// function passed as the `builder` argument to [showModalBottomSheet].
/// * [showBottomSheet] and [ScaffoldState.showBottomSheet], for showing
/// non-modal bottom sheets.
/// * [DraggableScrollableSheet], creates a bottom sheet that grows
/// and then becomes scrollable once it reaches its maximum size.
/// * [DisplayFeatureSubScreen], which documents the specifics of how
/// [DisplayFeature]s can split the screen into sub-screens.
/// * The Material 2 spec at <https://m2.material.io/components/sheets-bottom>.
/// * The Material 3 spec at <https://m3.material.io/components/bottom-sheets/overview>.
/// * [AnimationStyle], which is used to override the modal bottom sheet
/// animation duration and reverse animation duration.
Future<T?> showModalBottomSheet<T>({
required BuildContext context,
required WidgetBuilder builder,
Color? backgroundColor,
String? barrierLabel,
double? elevation,
ShapeBorder? shape,
Clip? clipBehavior,
BoxConstraints? constraints,
Color? barrierColor,
bool isScrollControlled = false,
double scrollControlDisabledMaxHeightRatio = _kDefaultScrollControlDisabledMaxHeightRatio,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true,
bool? showDragHandle,
bool useSafeArea = false,
RouteSettings? routeSettings,
AnimationController? transitionAnimationController,
Offset? anchorPoint,
AnimationStyle? sheetAnimationStyle,
bool? requestFocus,
}) {
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final NavigatorState navigator = Navigator.of(context, rootNavigator: useRootNavigator);
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
return navigator.push(
ModalBottomSheetRoute<T>(
builder: builder,
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
isScrollControlled: isScrollControlled,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
barrierLabel: barrierLabel ?? localizations.scrimLabel,
barrierOnTapHint: localizations.scrimOnTapHint(localizations.bottomSheetLabel),
backgroundColor: backgroundColor,
elevation: elevation,
shape: shape,
clipBehavior: clipBehavior,
constraints: constraints,
isDismissible: isDismissible,
modalBarrierColor: barrierColor ?? Theme.of(context).bottomSheetTheme.modalBarrierColor,
enableDrag: enableDrag,
showDragHandle: showDragHandle,
settings: routeSettings,
transitionAnimationController: transitionAnimationController,
anchorPoint: anchorPoint,
useSafeArea: useSafeArea,
sheetAnimationStyle: sheetAnimationStyle,
requestFocus: requestFocus,
),
);
}