| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| import 'button_bar.dart'; |
| import 'colors.dart'; |
| import 'debug.dart'; |
| import 'dialog_theme.dart'; |
| import 'ink_well.dart'; |
| import 'material.dart'; |
| import 'material_localizations.dart'; |
| import 'theme.dart'; |
| |
| // Examples can assume: |
| // enum Department { treasury, state } |
| // BuildContext context; |
| |
| /// A material design dialog. |
| /// |
| /// This dialog widget does not have any opinion about the contents of the |
| /// dialog. Rather than using this widget directly, consider using [AlertDialog] |
| /// or [SimpleDialog], which implement specific kinds of material design |
| /// dialogs. |
| /// |
| /// See also: |
| /// |
| /// * [AlertDialog], for dialogs that have a message and some buttons. |
| /// * [SimpleDialog], for dialogs that offer a variety of options. |
| /// * [showDialog], which actually displays the dialog and returns its result. |
| /// * <https://material.io/design/components/dialogs.html> |
| class Dialog extends StatelessWidget { |
| /// Creates a dialog. |
| /// |
| /// Typically used in conjunction with [showDialog]. |
| const Dialog({ |
| Key key, |
| this.backgroundColor, |
| this.elevation, |
| this.insetAnimationDuration = const Duration(milliseconds: 100), |
| this.insetAnimationCurve = Curves.decelerate, |
| this.shape, |
| this.child, |
| }) : super(key: key); |
| |
| /// {@template flutter.material.dialog.backgroundColor} |
| /// The background color of the surface of this [Dialog]. |
| /// |
| /// This sets the [Material.color] on this [Dialog]'s [Material]. |
| /// |
| /// If `null`, [ThemeData.cardColor] is used. |
| /// {@endtemplate} |
| final Color backgroundColor; |
| |
| /// {@template flutter.material.dialog.elevation} |
| /// The z-coordinate of this [Dialog]. |
| /// |
| /// If null then [DialogTheme.elevation] is used, and if that's null then the |
| /// dialog's elevation is 24.0. |
| /// {@endtemplate} |
| /// {@macro flutter.material.material.elevation} |
| final double elevation; |
| |
| /// The duration of the animation to show when the system keyboard intrudes |
| /// into the space that the dialog is placed in. |
| /// |
| /// Defaults to 100 milliseconds. |
| final Duration insetAnimationDuration; |
| |
| /// The curve to use for the animation shown when the system keyboard intrudes |
| /// into the space that the dialog is placed in. |
| /// |
| /// Defaults to [Curves.fastOutSlowIn]. |
| final Curve insetAnimationCurve; |
| |
| /// {@template flutter.material.dialog.shape} |
| /// The shape of this dialog's border. |
| /// |
| /// Defines the dialog's [Material.shape]. |
| /// |
| /// The default shape is a [RoundedRectangleBorder] with a radius of 2.0. |
| /// {@endtemplate} |
| final ShapeBorder shape; |
| |
| /// The widget below this widget in the tree. |
| /// |
| /// {@macro flutter.widgets.child} |
| final Widget child; |
| |
| // TODO(johnsonmh): Update default dialog border radius to 4.0 to match material spec. |
| static const RoundedRectangleBorder _defaultDialogShape = |
| RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))); |
| static const double _defaultElevation = 24.0; |
| |
| @override |
| Widget build(BuildContext context) { |
| final DialogTheme dialogTheme = DialogTheme.of(context); |
| return AnimatedPadding( |
| padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), |
| duration: insetAnimationDuration, |
| curve: insetAnimationCurve, |
| child: MediaQuery.removeViewInsets( |
| removeLeft: true, |
| removeTop: true, |
| removeRight: true, |
| removeBottom: true, |
| context: context, |
| child: Center( |
| child: ConstrainedBox( |
| constraints: const BoxConstraints(minWidth: 280.0), |
| child: Material( |
| color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor, |
| elevation: elevation ?? dialogTheme.elevation ?? _defaultElevation, |
| shape: shape ?? dialogTheme.shape ?? _defaultDialogShape, |
| type: MaterialType.card, |
| child: child, |
| ), |
| ), |
| ), |
| ), |
| ); |
| } |
| } |
| |
| /// A material design alert dialog. |
| /// |
| /// An alert dialog informs the user about situations that require |
| /// acknowledgement. An alert dialog has an optional title and an optional list |
| /// of actions. The title is displayed above the content and the actions are |
| /// displayed below the content. |
| /// |
| /// If the content is too large to fit on the screen vertically, the dialog will |
| /// display the title and the actions and let the content overflow, which is |
| /// rarely desired. Consider using a scrolling widget for [content], such as |
| /// [SingleChildScrollView], to avoid overflow. (However, be aware that since |
| /// [AlertDialog] tries to size itself using the intrinsic dimensions of its |
| /// children, widgets such as [ListView], [GridView], and [CustomScrollView], |
| /// which use lazy viewports, will not work. If this is a problem, consider |
| /// using [Dialog] directly.) |
| /// |
| /// For dialogs that offer the user a choice between several options, consider |
| /// using a [SimpleDialog]. |
| /// |
| /// Typically passed as the child widget to [showDialog], which displays the |
| /// dialog. |
| /// |
| /// {@tool sample} |
| /// |
| /// This snippet shows a method in a [State] which, when called, displays a dialog box |
| /// and returns a [Future] that completes when the dialog is dismissed. |
| /// |
| /// ```dart |
| /// Future<void> _neverSatisfied() async { |
| /// return showDialog<void>( |
| /// context: context, |
| /// barrierDismissible: false, // user must tap button! |
| /// builder: (BuildContext context) { |
| /// return AlertDialog( |
| /// title: Text('Rewind and remember'), |
| /// content: SingleChildScrollView( |
| /// child: ListBody( |
| /// children: <Widget>[ |
| /// Text('You will never be satisfied.'), |
| /// Text('You\’re like me. I’m never satisfied.'), |
| /// ], |
| /// ), |
| /// ), |
| /// actions: <Widget>[ |
| /// FlatButton( |
| /// child: Text('Regret'), |
| /// onPressed: () { |
| /// Navigator.of(context).pop(); |
| /// }, |
| /// ), |
| /// ], |
| /// ); |
| /// }, |
| /// ); |
| /// } |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [SimpleDialog], which handles the scrolling of the contents but has no [actions]. |
| /// * [Dialog], on which [AlertDialog] and [SimpleDialog] are based. |
| /// * [CupertinoAlertDialog], an iOS-styled alert dialog. |
| /// * [showDialog], which actually displays the dialog and returns its result. |
| /// * <https://material.io/design/components/dialogs.html#alert-dialog> |
| class AlertDialog extends StatelessWidget { |
| /// Creates an alert dialog. |
| /// |
| /// Typically used in conjunction with [showDialog]. |
| /// |
| /// The [contentPadding] must not be null. The [titlePadding] defaults to |
| /// null, which implies a default that depends on the values of the other |
| /// properties. See the documentation of [titlePadding] for details. |
| const AlertDialog({ |
| Key key, |
| this.title, |
| this.titlePadding, |
| this.titleTextStyle, |
| this.content, |
| this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0), |
| this.contentTextStyle, |
| this.actions, |
| this.backgroundColor, |
| this.elevation, |
| this.semanticLabel, |
| this.shape, |
| }) : assert(contentPadding != null), |
| super(key: key); |
| |
| /// The (optional) title of the dialog is displayed in a large font at the top |
| /// of the dialog. |
| /// |
| /// Typically a [Text] widget. |
| final Widget title; |
| |
| /// Padding around the title. |
| /// |
| /// If there is no title, no padding will be provided. Otherwise, this padding |
| /// is used. |
| /// |
| /// This property defaults to providing 24 pixels on the top, left, and right |
| /// of the title. If the [content] is not null, then no bottom padding is |
| /// provided (but see [contentPadding]). If it _is_ null, then an extra 20 |
| /// pixels of bottom padding is added to separate the [title] from the |
| /// [actions]. |
| final EdgeInsetsGeometry titlePadding; |
| |
| /// Style for the text in the [title] of this [AlertDialog]. |
| /// |
| /// If null, [DialogTheme.titleTextStyle] is used, if that's null, defaults to |
| /// [ThemeData.textTheme.title]. |
| final TextStyle titleTextStyle; |
| |
| /// The (optional) content of the dialog is displayed in the center of the |
| /// dialog in a lighter font. |
| /// |
| /// Typically this is a [SingleChildScrollView] that contains the dialog's |
| /// message. As noted in the [AlertDialog] documentation, it's important |
| /// to use a [SingleChildScrollView] if there's any risk that the content |
| /// will not fit. |
| final Widget content; |
| |
| /// Padding around the content. |
| /// |
| /// If there is no content, no padding will be provided. Otherwise, padding of |
| /// 20 pixels is provided above the content to separate the content from the |
| /// title, and padding of 24 pixels is provided on the left, right, and bottom |
| /// to separate the content from the other edges of the dialog. |
| final EdgeInsetsGeometry contentPadding; |
| |
| /// Style for the text in the [content] of this [AlertDialog]. |
| /// |
| /// If null, [DialogTheme.contentTextStyle] is used, if that's null, defaults |
| /// to [ThemeData.textTheme.subhead]. |
| final TextStyle contentTextStyle; |
| |
| /// The (optional) set of actions that are displayed at the bottom of the |
| /// dialog. |
| /// |
| /// Typically this is a list of [FlatButton] widgets. |
| /// |
| /// These widgets will be wrapped in a [ButtonBar], which introduces 8 pixels |
| /// of padding on each side. |
| /// |
| /// If the [title] is not null but the [content] _is_ null, then an extra 20 |
| /// pixels of padding is added above the [ButtonBar] to separate the [title] |
| /// from the [actions]. |
| final List<Widget> actions; |
| |
| /// {@macro flutter.material.dialog.backgroundColor} |
| final Color backgroundColor; |
| |
| /// {@macro flutter.material.dialog.elevation} |
| /// {@macro flutter.material.material.elevation} |
| final double elevation; |
| |
| /// The semantic label of the dialog used by accessibility frameworks to |
| /// announce screen transitions when the dialog is opened and closed. |
| /// |
| /// If this label is not provided, a semantic label will be inferred from the |
| /// [title] if it is not null. If there is no title, the label will be taken |
| /// from [MaterialLocalizations.alertDialogLabel]. |
| /// |
| /// See also: |
| /// |
| /// * [SemanticsConfiguration.isRouteName], for a description of how this |
| /// value is used. |
| final String semanticLabel; |
| |
| /// {@macro flutter.material.dialog.shape} |
| final ShapeBorder shape; |
| |
| @override |
| Widget build(BuildContext context) { |
| assert(debugCheckHasMaterialLocalizations(context)); |
| final ThemeData theme = Theme.of(context); |
| final DialogTheme dialogTheme = DialogTheme.of(context); |
| final List<Widget> children = <Widget>[]; |
| String label = semanticLabel; |
| |
| if (title != null) { |
| children.add(Padding( |
| padding: titlePadding ?? EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0), |
| child: DefaultTextStyle( |
| style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title, |
| child: Semantics( |
| child: title, |
| namesRoute: true, |
| container: true, |
| ), |
| ), |
| )); |
| } else { |
| switch (theme.platform) { |
| case TargetPlatform.iOS: |
| label = semanticLabel; |
| break; |
| case TargetPlatform.android: |
| case TargetPlatform.fuchsia: |
| label = semanticLabel ?? MaterialLocalizations.of(context)?.alertDialogLabel; |
| } |
| } |
| |
| if (content != null) { |
| children.add(Flexible( |
| child: Padding( |
| padding: contentPadding, |
| child: DefaultTextStyle( |
| style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead, |
| child: content, |
| ), |
| ), |
| )); |
| } |
| |
| if (actions != null) { |
| children.add(ButtonBar( |
| children: actions, |
| )); |
| } |
| |
| Widget dialogChild = IntrinsicWidth( |
| child: Column( |
| mainAxisSize: MainAxisSize.min, |
| crossAxisAlignment: CrossAxisAlignment.stretch, |
| children: children, |
| ), |
| ); |
| |
| if (label != null) |
| dialogChild = Semantics( |
| namesRoute: true, |
| label: label, |
| child: dialogChild, |
| ); |
| |
| return Dialog( |
| backgroundColor: backgroundColor, |
| elevation: elevation, |
| shape: shape, |
| child: dialogChild, |
| ); |
| } |
| } |
| |
| /// An option used in a [SimpleDialog]. |
| /// |
| /// A simple dialog offers the user a choice between several options. This |
| /// widget is commonly used to represent each of the options. If the user |
| /// selects this option, the widget will call the [onPressed] callback, which |
| /// typically uses [Navigator.pop] to close the dialog. |
| /// |
| /// The padding on a [SimpleDialogOption] is configured to combine with the |
| /// default [SimpleDialog.contentPadding] so that each option ends up 8 pixels |
| /// from the other vertically, with 20 pixels of spacing between the dialog's |
| /// title and the first option, and 24 pixels of spacing between the last option |
| /// and the bottom of the dialog. |
| /// |
| /// {@tool sample} |
| /// |
| /// ```dart |
| /// SimpleDialogOption( |
| /// onPressed: () { Navigator.pop(context, Department.treasury); }, |
| /// child: const Text('Treasury department'), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [SimpleDialog], for a dialog in which to use this widget. |
| /// * [showDialog], which actually displays the dialog and returns its result. |
| /// * [FlatButton], which are commonly used as actions in other kinds of |
| /// dialogs, such as [AlertDialog]s. |
| /// * <https://material.io/design/components/dialogs.html#simple-dialog> |
| class SimpleDialogOption extends StatelessWidget { |
| /// Creates an option for a [SimpleDialog]. |
| const SimpleDialogOption({ |
| Key key, |
| this.onPressed, |
| this.child, |
| }) : super(key: key); |
| |
| /// The callback that is called when this option is selected. |
| /// |
| /// If this is set to null, the option cannot be selected. |
| /// |
| /// When used in a [SimpleDialog], this will typically call [Navigator.pop] |
| /// with a value for [showDialog] to complete its future with. |
| final VoidCallback onPressed; |
| |
| /// The widget below this widget in the tree. |
| /// |
| /// Typically a [Text] widget. |
| final Widget child; |
| |
| @override |
| Widget build(BuildContext context) { |
| return InkWell( |
| onTap: onPressed, |
| child: Padding( |
| padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0), |
| child: child, |
| ), |
| ); |
| } |
| } |
| |
| /// A simple material design dialog. |
| /// |
| /// A simple dialog offers the user a choice between several options. A simple |
| /// dialog has an optional title that is displayed above the choices. |
| /// |
| /// Choices are normally represented using [SimpleDialogOption] widgets. If |
| /// other widgets are used, see [contentPadding] for notes regarding the |
| /// conventions for obtaining the spacing expected by Material Design. |
| /// |
| /// For dialogs that inform the user about a situation, consider using an |
| /// [AlertDialog]. |
| /// |
| /// Typically passed as the child widget to [showDialog], which displays the |
| /// dialog. |
| /// |
| /// {@tool sample} |
| /// |
| /// In this example, the user is asked to select between two options. These |
| /// options are represented as an enum. The [showDialog] method here returns |
| /// a [Future] that completes to a value of that enum. If the user cancels |
| /// the dialog (e.g. by hitting the back button on Android, or tapping on the |
| /// mask behind the dialog) then the future completes with the null value. |
| /// |
| /// The return value in this example is used as the index for a switch statement. |
| /// One advantage of using an enum as the return value and then using that to |
| /// drive a switch statement is that the analyzer will flag any switch statement |
| /// that doesn't mention every value in the enum. |
| /// |
| /// ```dart |
| /// Future<void> _askedToLead() async { |
| /// switch (await showDialog<Department>( |
| /// context: context, |
| /// builder: (BuildContext context) { |
| /// return SimpleDialog( |
| /// title: const Text('Select assignment'), |
| /// children: <Widget>[ |
| /// SimpleDialogOption( |
| /// onPressed: () { Navigator.pop(context, Department.treasury); }, |
| /// child: const Text('Treasury department'), |
| /// ), |
| /// SimpleDialogOption( |
| /// onPressed: () { Navigator.pop(context, Department.state); }, |
| /// child: const Text('State department'), |
| /// ), |
| /// ], |
| /// ); |
| /// } |
| /// )) { |
| /// case Department.treasury: |
| /// // Let's go. |
| /// // ... |
| /// break; |
| /// case Department.state: |
| /// // ... |
| /// break; |
| /// } |
| /// } |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [SimpleDialogOption], which are options used in this type of dialog. |
| /// * [AlertDialog], for dialogs that have a row of buttons below the body. |
| /// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based. |
| /// * [showDialog], which actually displays the dialog and returns its result. |
| /// * <https://material.io/design/components/dialogs.html#simple-dialog> |
| class SimpleDialog extends StatelessWidget { |
| /// Creates a simple dialog. |
| /// |
| /// Typically used in conjunction with [showDialog]. |
| /// |
| /// The [titlePadding] and [contentPadding] arguments must not be null. |
| const SimpleDialog({ |
| Key key, |
| this.title, |
| this.titlePadding = const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0), |
| this.children, |
| this.contentPadding = const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0), |
| this.backgroundColor, |
| this.elevation, |
| this.semanticLabel, |
| this.shape, |
| }) : assert(titlePadding != null), |
| assert(contentPadding != null), |
| super(key: key); |
| |
| /// The (optional) title of the dialog is displayed in a large font at the top |
| /// of the dialog. |
| /// |
| /// Typically a [Text] widget. |
| final Widget title; |
| |
| /// Padding around the title. |
| /// |
| /// If there is no title, no padding will be provided. |
| /// |
| /// By default, this provides the recommend Material Design padding of 24 |
| /// pixels around the left, top, and right edges of the title. |
| /// |
| /// See [contentPadding] for the conventions regarding padding between the |
| /// [title] and the [children]. |
| final EdgeInsetsGeometry titlePadding; |
| |
| /// The (optional) content of the dialog is displayed in a |
| /// [SingleChildScrollView] underneath the title. |
| /// |
| /// Typically a list of [SimpleDialogOption]s. |
| final List<Widget> children; |
| |
| /// Padding around the content. |
| /// |
| /// By default, this is 12 pixels on the top and 16 pixels on the bottom. This |
| /// is intended to be combined with children that have 24 pixels of padding on |
| /// the left and right, and 8 pixels of padding on the top and bottom, so that |
| /// the content ends up being indented 20 pixels from the title, 24 pixels |
| /// from the bottom, and 24 pixels from the sides. |
| /// |
| /// The [SimpleDialogOption] widget uses such padding. |
| /// |
| /// If there is no [title], the [contentPadding] should be adjusted so that |
| /// the top padding ends up being 24 pixels. |
| final EdgeInsetsGeometry contentPadding; |
| |
| /// {@macro flutter.material.dialog.backgroundColor} |
| final Color backgroundColor; |
| |
| /// {@macro flutter.material.dialog.elevation} |
| /// {@macro flutter.material.material.elevation} |
| final double elevation; |
| |
| /// The semantic label of the dialog used by accessibility frameworks to |
| /// announce screen transitions when the dialog is opened and closed. |
| /// |
| /// If this label is not provided, a semantic label will be inferred from the |
| /// [title] if it is not null. If there is no title, the label will be taken |
| /// from [MaterialLocalizations.dialogLabel]. |
| /// |
| /// See also: |
| /// |
| /// * [SemanticsConfiguration.isRouteName], for a description of how this |
| /// value is used. |
| final String semanticLabel; |
| |
| /// {@macro flutter.material.dialog.shape} |
| final ShapeBorder shape; |
| |
| @override |
| Widget build(BuildContext context) { |
| assert(debugCheckHasMaterialLocalizations(context)); |
| final List<Widget> body = <Widget>[]; |
| String label = semanticLabel; |
| |
| final ThemeData theme = Theme.of(context); |
| |
| if (title != null) { |
| body.add(Padding( |
| padding: titlePadding, |
| child: DefaultTextStyle( |
| style: theme.textTheme.title, |
| child: Semantics(namesRoute: true, child: title), |
| ), |
| )); |
| } else { |
| switch (theme.platform) { |
| case TargetPlatform.iOS: |
| label = semanticLabel; |
| break; |
| case TargetPlatform.android: |
| case TargetPlatform.fuchsia: |
| label = semanticLabel ?? MaterialLocalizations.of(context)?.dialogLabel; |
| } |
| } |
| |
| if (children != null) { |
| body.add(Flexible( |
| child: SingleChildScrollView( |
| padding: contentPadding, |
| child: ListBody(children: children), |
| ), |
| )); |
| } |
| |
| Widget dialogChild = IntrinsicWidth( |
| stepWidth: 56.0, |
| child: ConstrainedBox( |
| constraints: const BoxConstraints(minWidth: 280.0), |
| child: Column( |
| mainAxisSize: MainAxisSize.min, |
| crossAxisAlignment: CrossAxisAlignment.stretch, |
| children: body, |
| ), |
| ), |
| ); |
| |
| if (label != null) |
| dialogChild = Semantics( |
| namesRoute: true, |
| label: label, |
| child: dialogChild, |
| ); |
| return Dialog( |
| backgroundColor: backgroundColor, |
| elevation: elevation, |
| shape: shape, |
| child: dialogChild, |
| ); |
| } |
| } |
| |
| Widget _buildMaterialDialogTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { |
| return FadeTransition( |
| opacity: CurvedAnimation( |
| parent: animation, |
| curve: Curves.easeOut, |
| ), |
| child: child, |
| ); |
| } |
| |
| /// Displays a Material dialog above the current contents of the app, with |
| /// Material entrance and exit animations, modal barrier color, and modal |
| /// barrier behavior (dialog is dismissible with a tap on the barrier). |
| /// |
| /// This function takes a `builder` which typically builds a [Dialog] widget. |
| /// Content below the dialog is dimmed with a [ModalBarrier]. The widget |
| /// returned by the `builder` does not share a context with the location that |
| /// `showDialog` is originally called from. Use a [StatefulBuilder] or a |
| /// custom [StatefulWidget] if the dialog needs to update dynamically. |
| /// |
| /// The `context` argument is used to look up the [Navigator] and [Theme] for |
| /// the dialog. It is only used when the method is called. Its corresponding |
| /// widget can be safely removed from the tree before the dialog is closed. |
| /// |
| /// The `child` argument is deprecated, and should be replaced with `builder`. |
| /// |
| /// Returns a [Future] that resolves to the value (if any) that was passed to |
| /// [Navigator.pop] when the dialog was closed. |
| /// |
| /// The dialog route created by this method is pushed to the root navigator. |
| /// If the application has multiple [Navigator] objects, it may be necessary to |
| /// call `Navigator.of(context, rootNavigator: true).pop(result)` to close the |
| /// dialog rather than just `Navigator.pop(context, result)`. |
| /// |
| /// See also: |
| /// |
| /// * [AlertDialog], for dialogs that have a row of buttons below a body. |
| /// * [SimpleDialog], which handles the scrolling of the contents and does |
| /// not show buttons below its body. |
| /// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based. |
| /// * [showCupertinoDialog], which displays an iOS-style dialog. |
| /// * [showGeneralDialog], which allows for customization of the dialog popup. |
| /// * <https://material.io/design/components/dialogs.html> |
| Future<T> showDialog<T>({ |
| @required BuildContext context, |
| bool barrierDismissible = true, |
| @Deprecated( |
| 'Instead of using the "child" argument, return the child from a closure ' |
| 'provided to the "builder" argument. This will ensure that the BuildContext ' |
| 'is appropriate for widgets built in the dialog.' |
| ) Widget child, |
| WidgetBuilder builder, |
| }) { |
| assert(child == null || builder == null); |
| assert(debugCheckHasMaterialLocalizations(context)); |
| |
| final ThemeData theme = Theme.of(context, shadowThemeOnly: true); |
| return showGeneralDialog( |
| context: context, |
| pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { |
| final Widget pageChild = child ?? Builder(builder: builder); |
| return SafeArea( |
| child: Builder( |
| builder: (BuildContext context) { |
| return theme != null |
| ? Theme(data: theme, child: pageChild) |
| : pageChild; |
| } |
| ), |
| ); |
| }, |
| barrierDismissible: barrierDismissible, |
| barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, |
| barrierColor: Colors.black54, |
| transitionDuration: const Duration(milliseconds: 150), |
| transitionBuilder: _buildMaterialDialogTransitions, |
| ); |
| } |