Search code examples
flutterdartflutter-alertdialog

Flutter - custom alert dialog not showing


I am building a custom alert dialog using flutter/Dart and a Custom Show Dialog class that I got from Github and for a reason or another the dialog is not showing.

Q: How to get the dialog to show properly?

PS resultsDialog(a,b) is being called on a button click elsewhere.

Here's my code for the Alert dialog:

Future<void> resultsDialog(String sq, String sl) async {
  BuildContext ctx;
  CustomAlertDialog dialog = new CustomAlertDialog(
    content: Material(
      type: MaterialType.card,
      child: new Container(
        margin: EdgeInsets.only(left: 26.0, right: 26.0),
        decoration: new BoxDecoration(
        shape: BoxShape.rectangle,
        color: const Color(0xFFFFFF),
        borderRadius:
          new BorderRadius.all(new Radius.circular(32.0)),
        ),
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            // dialog top
            new Expanded(
                //...
            ),
            // dialog center row
            new Expanded(
                //...
            ),
            // dialog bottom row
            new Expanded(
                //...
            ),
          ],
        ),
      ),
    ),
  );
  customShowDialog(context: ctx, child: dialog);
}

Expected result:

enter image description here

PS I got the inner rows takes care of so the problem here is only getting the dialog to show up and prevent it from being dismissed that's all


Solution

  • You need to pass context from your parent widget
    and in your resultsDialog add a parameter BuildContext ctx
    You can copy paste run full code below

    code snippet

     void _incrementCounter() {
        resultsDialog(context, "a", "b");
        setState(() {
    
    Future<void> resultsDialog(BuildContext ctx, String sq, String sl) async {
      //BuildContext ctx;
      CustomAlertDialog dialog = new CustomAlertDialog(
        content: Material(
          type: MaterialType.card,
          child: new Container(
            margin: EdgeInsets.only(left: 26.0, right: 26.0),
            decoration: new BoxDecoration(
              shape: BoxShape.rectangle,
              color: const Color(0xFFFFFF),
              borderRadius:
              new BorderRadius.all(new Radius.circular(32.0)),
            ),
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                // dialog top
                Text('Dialog OK'),
                Text('${sq}'),
                Text('${sl}'),
              ],
            ),
          ),
        ),
      );
      customShowDialog(context: ctx, child: dialog);
    }
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'dart:async';
    import 'dart:ui';
    
    import 'package:flutter/foundation.dart';
    import 'package:flutter/widgets.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      // This widget is the home page of your application. It is stateful, meaning
      // that it has a State object (defined below) that contains fields that affect
      // how it looks.
    
      // This class is the configuration for the state. It holds the values (in this
      // case the title) provided by the parent (in this case the App widget) and
      // used by the build method of the State. Fields in a Widget subclass are
      // always marked "final".
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        resultsDialog(context, "a", "b");
        setState(() {
          // This call to setState tells the Flutter framework that something has
          // changed in this State, which causes it to rerun the build method below
          // so that the display can reflect the updated values. If we changed
          // _counter without calling setState(), then the build method would not be
          // called again, and so nothing would appear to happen.
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        // This method is rerun every time setState is called, for instance as done
        // by the _incrementCounter method above.
        //
        // The Flutter framework has been optimized to make rerunning build methods
        // fast, so that you can just rebuild anything that needs updating rather
        // than having to individually change instances of widgets.
        return Scaffold(
          appBar: AppBar(
            // Here we take the value from the MyHomePage object that was created by
            // the App.build method, and use it to set our appbar title.
            title: Text(widget.title),
          ),
          body: Center(
            // Center is a layout widget. It takes a single child and positions it
            // in the middle of the parent.
            child: Column(
              // Column is also a layout widget. It takes a list of children and
              // arranges them vertically. By default, it sizes itself to fit its
              // children horizontally, and tries to be as tall as its parent.
              //
              // Invoke "debug painting" (press "p" in the console, choose the
              // "Toggle Debug Paint" action from the Flutter Inspector in Android
              // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
              // to see the wireframe for each widget.
              //
              // Column has various properties to control how it sizes itself and
              // how it positions its children. Here we use mainAxisAlignment to
              // center the children vertically; the main axis here is the vertical
              // axis because Columns are vertical (the cross axis would be
              // horizontal).
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.display1,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    
    Future<void> resultsDialog(BuildContext ctx, String sq, String sl) async {
      //BuildContext ctx;
      CustomAlertDialog dialog = new CustomAlertDialog(
        content: Material(
          type: MaterialType.card,
          child: new Container(
            margin: EdgeInsets.only(left: 26.0, right: 26.0),
            decoration: new BoxDecoration(
              shape: BoxShape.rectangle,
              color: const Color(0xFFFFFF),
              borderRadius:
              new BorderRadius.all(new Radius.circular(32.0)),
            ),
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                // dialog top
                Text('Dialog OK'),
                Text('${sq}'),
                Text('${sl}'),
              ],
            ),
          ),
        ),
      );
      customShowDialog(context: ctx, child: dialog);
    }
    
    // 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.
    
    
    
    // Examples can assume:
    // enum Department { treasury, state }
    
    /// 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.google.com/components/dialogs.html>
    class Dialog extends StatelessWidget {
      /// Creates a dialog.
      ///
      /// Typically used in conjunction with [showDialog].
      const Dialog({
        Key key,
        this.child,
        this.insetAnimationDuration: const Duration(milliseconds: 100),
        this.insetAnimationCurve: Curves.decelerate,
      }) : super(key: key);
    
      /// The widget below this widget in the tree.
      ///
      /// {@macro flutter.widgets.child}
      final Widget child;
    
      /// 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;
    
      Color _getColor(BuildContext context) {
        return Theme.of(context).dialogBackgroundColor;
      }
    
      @override
      Widget build(BuildContext context) {
        return new AnimatedPadding(
          padding: MediaQuery.of(context).viewInsets +
              const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
          duration: insetAnimationDuration,
          curve: insetAnimationCurve,
          child: new MediaQuery.removeViewInsets(
            removeLeft: true,
            removeTop: true,
            removeRight: true,
            removeBottom: true,
            context: context,
            child: new Center(
              child: new ConstrainedBox(
                constraints: const BoxConstraints(minWidth: 280.0),
                child: new Material(
                  borderRadius: BorderRadius.all(Radius.circular(20.0)),
                  elevation: 30.0,
                  color: _getColor(context),
                  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. Consider
    /// using a scrolling widget, such as [ListView], for [content] to avoid
    /// overflow.
    ///
    /// 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.
    ///
    /// ## Sample code
    ///
    /// 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<Null> _neverSatisfied() async {
    ///   return showDialog<Null>(
    ///     context: context,
    ///     barrierDismissible: false, // user must tap button!
    ///     builder: (BuildContext context) {
    ///       return new AlertDialog(
    ///         title: new Text('Rewind and remember'),
    ///         content: new SingleChildScrollView(
    ///           child: new ListBody(
    ///             children: <Widget>[
    ///               new Text('You will never be satisfied.'),
    ///               new Text('You\’re like me. I’m never satisfied.'),
    ///             ],
    ///           ),
    ///         ),
    ///         actions: <Widget>[
    ///           new FlatButton(
    ///             child: new Text('Regret'),
    ///             onPressed: () {
    ///               Navigator.of(context).pop();
    ///             },
    ///           ),
    ///         ],
    ///       );
    ///     },
    ///   );
    /// }
    /// ```
    ///
    /// See also:
    ///
    ///  * [SimpleDialog], which handles the scrolling of the contents but has no [actions].
    ///  * [Dialog], on which [AlertDialog] and [SimpleDialog] are based.
    ///  * [showDialog], which actually displays the dialog and returns its result.
    ///  * <https://material.google.com/components/dialogs.html#dialogs-alerts>
    class CustomAlertDialog 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 CustomAlertDialog({
        Key key,
        this.title,
        this.titlePadding,
        this.content,
        this.contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),
        this.actions,
        this.semanticLabel,
      })  : 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;
    
      /// The (optional) content of the dialog is displayed in the center of the
      /// dialog in a lighter font.
      ///
      /// Typically, this is a [ListView] containing the contents of the dialog.
      /// Using a [ListView] ensures that the contents can scroll if they are too
      /// big to fit on the display.
      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;
    
      /// 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;
    
      /// 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 infered 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;
    
      @override
      Widget build(BuildContext context) {
        final List<Widget> children = <Widget>[];
        String label = semanticLabel;
    
        if (title != null) {
          children.add(new Padding(
            padding: titlePadding ??
                new EdgeInsets.fromLTRB(
                    24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
            child: new DefaultTextStyle(
              style: Theme.of(context).textTheme.title,
              child: new Semantics(child: title, namesRoute: true),
            ),
          ));
        } else {
          switch (defaultTargetPlatform) {
            case TargetPlatform.iOS:
              label = semanticLabel;
              break;
            case TargetPlatform.android:
            case TargetPlatform.fuchsia:
              label = semanticLabel ??
                  MaterialLocalizations.of(context)?.alertDialogLabel;
          }
        }
    
        if (content != null) {
          children.add(new Flexible(
            child: new Padding(
              padding: contentPadding,
              child: new DefaultTextStyle(
                style: Theme.of(context).textTheme.subhead,
                child: content,
              ),
            ),
          ));
        }
    
        if (actions != null) {
          children.add(new ButtonTheme.bar(
            child: new ButtonBar(
              children: actions,
            ),
          ));
        }
    
        Widget dialogChild = new IntrinsicWidth(
          child: new Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: children,
          ),
        );
    
        if (label != null)
          dialogChild =
          new Semantics(namesRoute: true, label: label, child: dialogChild);
    
        return new Dialog(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.
    ///
    /// ## Sample code
    ///
    /// ```dart
    /// new SimpleDialogOption(
    ///   onPressed: () { Navigator.pop(context, Department.treasury); },
    ///   child: const Text('Treasury department'),
    /// )
    /// ```
    ///
    /// 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.google.com/components/dialogs.html#dialogs-simple-dialogs>
    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 new InkWell(
          onTap: onPressed,
          child: new 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.
    ///
    /// ## Sample code
    ///
    /// 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<Null> _askedToLead() async {
    ///   switch (await showDialog<Department>(
    ///     context: context,
    ///     builder: (BuildContext context) {
    ///       return new SimpleDialog(
    ///         title: const Text('Select assignment'),
    ///         children: <Widget>[
    ///           new SimpleDialogOption(
    ///             onPressed: () { Navigator.pop(context, Department.treasury); },
    ///             child: const Text('Treasury department'),
    ///           ),
    ///           new SimpleDialogOption(
    ///             onPressed: () { Navigator.pop(context, Department.state); },
    ///             child: const Text('State department'),
    ///           ),
    ///         ],
    ///       );
    ///     }
    ///   )) {
    ///     case Department.treasury:
    ///       // Let's go.
    ///       // ...
    ///     break;
    ///     case Department.state:
    ///       // ...
    ///     break;
    ///   }
    /// }
    /// ```
    ///
    /// 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.google.com/components/dialogs.html#dialogs-simple-dialogs>
    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.semanticLabel,
      })  : 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;
    
      /// 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 infered 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;
    
      @override
      Widget build(BuildContext context) {
        final List<Widget> body = <Widget>[];
        String label = semanticLabel;
    
        if (title != null) {
          body.add(new Padding(
              padding: titlePadding,
              child: new DefaultTextStyle(
                style: Theme.of(context).textTheme.title,
                child: new Semantics(namesRoute: true, child: title),
              )));
        } else {
          switch (defaultTargetPlatform) {
            case TargetPlatform.iOS:
              label = semanticLabel;
              break;
            case TargetPlatform.android:
            case TargetPlatform.fuchsia:
              label =
                  semanticLabel ?? MaterialLocalizations.of(context)?.dialogLabel;
          }
        }
    
        if (children != null) {
          body.add(new Flexible(
              child: new SingleChildScrollView(
                padding: contentPadding,
                child: new ListBody(children: children),
              )));
        }
    
        Widget dialogChild = new IntrinsicWidth(
          stepWidth: 56.0,
          child: new ConstrainedBox(
            constraints: const BoxConstraints(minWidth: 280.0),
            child: new Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: body,
            ),
          ),
        );
    
        if (label != null)
          dialogChild = new Semantics(
            namesRoute: true,
            label: label,
            child: dialogChild,
          );
        return new Dialog(child: dialogChild);
      }
    }
    
    class _DialogRoute<T> extends PopupRoute<T> {
      _DialogRoute({
        @required this.theme,
        bool barrierDismissible: true,
        this.barrierLabel,
        @required this.child,
        RouteSettings settings,
      })  : assert(barrierDismissible != null),
            _barrierDismissible = barrierDismissible,
            super(settings: settings);
    
      final Widget child;
      final ThemeData theme;
    
      @override
      Duration get transitionDuration => const Duration(milliseconds: 150);
    
      @override
      bool get barrierDismissible => _barrierDismissible;
      final bool _barrierDismissible;
    
      @override
      Color get barrierColor => Colors.black54;
    
      @override
      final String barrierLabel;
    
      @override
      Widget buildPage(BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation) {
        return new SafeArea(
          child: new Builder(builder: (BuildContext context) {
            final Widget annotatedChild = new Semantics(
              child: child,
              scopesRoute: true,
              explicitChildNodes: true,
            );
            return theme != null
                ? new Theme(data: theme, child: annotatedChild)
                : annotatedChild;
          }),
        );
      }
    
      @override
      Widget buildTransitions(BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation, Widget child) {
        return new FadeTransition(
            opacity: new CurvedAnimation(parent: animation, curve: Curves.easeOut),
            child: child);
      }
    }
    
    /// Displays a dialog above the current contents of the app.
    ///
    /// This function takes a `builder` which typically builds a [Dialog] widget.
    /// Content below the dialog is dimmed with a [ModalBarrier]. This widget 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 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.
    ///  * <https://material.google.com/components/dialogs.html>
    Future<T> customShowDialog<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);
      return Navigator.of(context, rootNavigator: true).push(new _DialogRoute<T>(
        child: child ?? new Builder(builder: builder),
        theme: Theme.of(context, shadowThemeOnly: true),
        barrierDismissible: barrierDismissible,
        barrierLabel:
        MaterialLocalizations.of(context).modalBarrierDismissLabel,
      ));
    }