A simple introduction

Recently, I used the display dialog box of Flutter to make some mistakes. By the way, I will make a summary so that you can avoid mistakes in the future. If there are any mistakes, please point them out.

Several scenarios and stomps for dialog boxes are described below.

  • Displays a normal dialog box
  • Displays a dialog box containing list items
  • The dialog box needs to be dynamically refreshed
  • Custom dialog box.

Let’s understand a few things

  • The dialog box is essentially a route of a routing page, which is managed by the Navigator, so it controls the display and hiding of the dialog box, and also calls the push and pop methods of navigator.of (context).

  • The showDialog() method will display the Material style dialog box, and the showCupertinoDialog() method will display the ios style dialog box. The showGeneralDialog() method is called by the showGeneralDialog() method. The final page is navigator.of (context, rootNavigator: true).push().

Basic to pass parameters: the context context, the builder is used to create display widget, barrierDismissible can control dialog click outside of the area whether to hide the dialog box.

  • You’ll notice that the showDialog() method returns a Future object that can be used to retrieve the data passed by the dialog. For example, if you want to know whether the user clicked on the confirm or cancel button of the dialog box, use navigator.of (context).pop(” some data “) when exiting the dialog box;
Future<T> showCupertinoDialog<T>({
  @required BuildContext context,
  @required WidgetBuilder builder,
});

Future<T> showDialog<T>({
  @required BuildContext context,
  bool barrierDismissible = true, WidgetBuilder builder, }) Future<T> showGeneralDialog<T>({ @required BuildContext context, @required RoutePageBuilder pageBuilder, bool barrierDismissible, String barrierLabel, Color barrierColor, Duration transitionDuration, RouteTransitionsBuilder transitionBuilder, }) { assert(pageBuilder ! = null); assert(! barrierDismissible || barrierLabel ! = null);return Navigator.of(context, rootNavigator: true).push<T>(_DialogRoute<T>(
    pageBuilder: pageBuilder,
    barrierDismissible: barrierDismissible,
    barrierLabel: barrierLabel,
    barrierColor: barrierColor,
    transitionDuration: transitionDuration,
    transitionBuilder: transitionBuilder,
  ));
}
Copy the code

Simple display dialog box

The main dialogs in Flutter are SimpleDialog and AlertDialog.

  • SimpleDialog, generally available with multiple SimpleDialogOptions, provides the user with several options.
  • An AlertDialog is a warning dialog box. The warning dialog box has an optional title and an optional list of actions options.

Show a simple SimpleDialog with the following code:

void showMySimpleDialog(BuildContext context) {
    showDialog(
        context: context,
        builder: (context) {
          return new SimpleDialog(
            title: new Text("SimpleDialog"),
            children: <Widget>[
              new SimpleDialogOption(
                child: new Text("SimpleDialogOption One"),
                onPressed: () {
                  Navigator.of(context).pop("SimpleDialogOption One");
                },
              ),
              new SimpleDialogOption(
                child: new Text("SimpleDialogOption Two"),
                onPressed: () {
                  Navigator.of(context).pop("SimpleDialogOption Two");
                },
              ),
              new SimpleDialogOption(
                child: new Text("SimpleDialogOption Three"),
                onPressed: () {
                  Navigator.of(context).pop("SimpleDialogOption Three"); },),,); }); }Copy the code

Show a simple Material style AlertDialog with the following code:

void showMyMaterialDialog(BuildContext context) {
    showDialog(
        context: context,
        builder: (context) {
          return new AlertDialog(
            title: new Text("title"),
            content: new Text("Content content content content content content content content content content"),
            actions: <Widget>[
              new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: new Text("Confirm"),
              ),
              new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: new Text("Cancel"),),,); }); }Copy the code

Show a simple ios-style AlertDialog with the following code:

void showMyCupertinoDialog(BuildContext context) {
    showCupertinoDialog(
        context: context,
        builder: (context) {
          return new CupertinoAlertDialog(
            title: new Text("title"),
            content: new Text("Content content content content content content content content content content"),
            actions: <Widget>[
              new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop("Hit OK");
                },
                child: new Text("Confirm"),
              ),
              new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop("Hit Cancel");
                },
                child: new Text("Cancel"),),,); }); }Copy the code

Display list item dialog box (stomped)

When constructing a dialog box, we always need to pass a Content object to construct the main content of the dialog box. In general, if the content is just simple content, that’s not a problem and can be displayed normally. But sometimes, we need to show a list dialog box. At this point, if there are too many items in the list, there will be some problems.

  • Use Column+SingleChildScrollView to display the list dialog.

Insert a SingleChildScrollView control to enable the inner child control to scroll without overflow error. SingleChildScrollView (SingleChildScrollView)

void showMyDialogWithColumn(BuildContext context) {
    showDialog(
        context: context,
        builder: (context) {
          return new AlertDialog(
            title: new Text("title"),
            content: new SingleChildScrollView(
              child: new Column(
                children: <Widget>[
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                  new SizedBox(
                    height: 100,
                    child: new Text("1"),
                  ),
                ],
              ),
            ),
            actions: <Widget>[
              new FlatButton(
                onPressed: () {},
                child: new Text("Confirm"),
              ),
              new FlatButton(
                onPressed: () {},
                child: new Text("Cancel"),),,); }); }Copy the code
  • Use ListView+ to specify the width and height of the Container to display the dialog box

You wrap the ListView in a Container with a specific width and height. If the Container does not define these attributes, an error is reported and the ListView cannot be displayed. (So far I have also solved this way, I don’t know if anyone has a better way.) Error as follows:

void showMyDialogWithListView(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        returnnew AlertDialog( content: New Container(/* Temporary workaround: To wrap the ListView in a Container with a specific width and height, if the Container does not define these attributes, an error will be reported and the ListView */ width will not be displayed: Mediaquery.of (context).size. Width * 0.9, height: mediaQuery.of (context).size. new ListView.builder( itemBuilder: (context, index) {return new SizedBox(
                height: 100,
                child: new Text("1")); }, itemCount: 10, shrinkWrap:true,),)); }); // An error will occur if the ListView is placed directly inside the dialog, for example, the following script will cause an error: I/flutter (10721): ═ ═ ╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ / / I/flutter (10721): The following assertion was thrown during performLayout(): // I/flutter (10721): RenderShrinkWrappingViewport does not support returning intrinsic dimensions. // I/flutter (10721): Calculating the intrinsic dimensions would require instantiating every child of the viewport,which
  //    I/flutter (10721): defeats the point of viewports being lazy.
  //    I/flutter (10721): If you are merely trying to shrink-wrap the viewport in the main axis direction, you should be able
  //    I/flutter (10721): to achieve that effect by just giving the viewport loose constraints, without needing to measure its
  //    I/flutter (10721): intrinsic dimensions.
  //    I/flutter (10721):
  //    I/flutter (10721): When the exception was thrown, this was the stack:
  //    I/flutter (10721): #0 RenderShrinkWrappingViewport.debugThrowIfNotCheckingIntrinsics.
      
        (package:flutter/src/rendering/viewport.dart:1544:9)
      
  //    I/flutter (10721): #1 RenderShrinkWrappingViewport.debugThrowIfNotCheckingIntrinsics (package:flutter/src/rendering/viewport.dart:1554:6)
  //    I/flutter (10721): #2 RenderViewportBase.computeMaxIntrinsicWidth (package:flutter/src/rendering/viewport.dart:321:12)
  //    I/flutter (10721): #3 RenderBox._computeIntrinsicDimension.
      
        (package:flutter/src/rendering/box.dart:1109:23)
      
  //    I/flutter (10721): #4 __InternalLinkedHashMap&_HashVMBase&MapMixin&_LinkedHashMapMixin.putIfAbsent (dart:collection/runtime/libcompact_hash.dart:277:23)
  //    I/flutter (10721): #5 RenderBox._computeIntrinsicDimension (package:flutter/src/rendering/box.dart:1107:41)
  //    I/flutter (10721): #6 RenderBox.getMaxIntrinsicWidth (package:flutter/src/rendering/box.dart:1291:12)
  //    I/flutter (10721): #7 _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.computeMaxIntrinsicWidth (package:flutter/src/rendering/proxy_box.dart:81:20)

  //        showDialog(context: context, builder: (context) {
  //      return new AlertDialog(title: new Text("title"),
  //        content: new SingleChildScrollView(
  //          child: new Container(
  //            height: 200,
  //            child: new ListView.builder(
  //              itemBuilder: (context, index) {
  //                return new SizedBox(height: 100, child: new Text("1")); // }, itemCount: 10, shrinkWrap:true,),
  //          ),
  //        ),
  //        actions: <Widget>[
  //          new FlatButton(onPressed: () {}, child: new Text("Confirm"),),
  //          new FlatButton(onPressed: () {}, child: new Text("Cancel"),), / /]); / /});Copy the code

Dialog box that needs to dynamically update the interface

Use StatefulBuilder to achieve some dialog scenes, need dialog dynamic update interface.

For example, display a checkbox in the dialog box, and then click to modify the checkbox display status. If it is the same as before the implementation of the dialog box method, is unable to achieve dynamic to refresh the dialog box interface.

The StatefulBuilder can contain a child with a state that you can call setState to refresh the interface.

The Builder parameter, which is used to create widgets that you want to display, can be used to refresh the interface by calling the setState parameter of type StateSetter.

typedef StatefulWidgetBuilder = Widget Function(BuildContext context, StateSetter setState); const StatefulBuilder({ Key key, @required this.builder }) : assert(builder ! = null), super(key: key);Copy the code

The code for this example is as follows:

 void showMyDialogWithStateBuilder(BuildContext context) {
    showDialog(
        context: context,
        builder: (context) {
          bool selected = false;
          return new AlertDialog(
            title: new Text("StatefulBuilder"),
            content:
                new StatefulBuilder(builder: (context, StateSetter setState) {
              return Container(
                child: new CheckboxListTile(
                    title: new Text("Options"),
                    value: selected,
                    onChanged: (bool) {
                      setState(() { selected = ! selected; }); })); })); }); }Copy the code

Custom Dialog

For example, if I wanted to display a chrysanthemum loading box, the above methods would not work. At this point, we need to customize a dialog box.

We can first look at the source implementation of the Dialog, and then just follow the source implementation, modify the line. Most of the code is consistent, so dialog displays such as animations and themes are consistent.

Here is an implementation of the build method in the Dialog source code. Simply modify the parameters passed to the child attribute.

 @override
  Widget build(BuildContext context) {
    final DialogTheme dialogTheme = DialogTheme.of(context);
    returnAnimatedPadding(padding: MediaQuery.of(context).viewinsets + const EdgeInsets. Symmetric (horizontal: 40.0, vertical: symmetric) 24.0), duration: insetAnimationDuration, curve: insetAnimationCurve, child: MediaQuery. RemoveViewInsets (removeLeft:true,
        removeTop: true,
        removeRight: true,
        removeBottom: true, context: context, // So all we need to do is change the child property to the widget we want to display. Child: Center(Child: ConstrainedBox(constraints: const BoxConstraints(minWidth: 280.0)), child: Material(elevation: 24.0 color: _getColor (context),type: MaterialType.card,
              child: child,
              shape: shape ?? dialogTheme.shape ?? _defaultDialogShape,
            ),
          ),
        ),
      ),
    );
  }
Copy the code

The following is an example of a custom load box Dialog, which is used to modify the source code of AlertDialog.

  void showMyCustomLoadingDialog(BuildContext context) {
    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (context) {
          returnnew MyCustomLoadingDialog(); }); } class MyCustomLoadingDialog extends StatelessWidget { @override Widget build(BuildContext context) { Duration insetAnimationDuration = const Duration(milliseconds: 100); Curve insetAnimationCurve = Curves.decelerate; RoundedRectangleBorder _defaultDialogShape = RoundedRectangleBorder( borderRadius: BorderRadius. All (Radius. Circular (2.0)));returnAnimatedPadding(padding: MediaQuery.of(context).viewinsets + const EdgeInsets. Symmetric (horizontal: 40.0, vertical: symmetric) 24.0), duration: insetAnimationDuration, curve: insetAnimationCurve, child: MediaQuery. RemoveViewInsets (removeLeft:true,
        removeTop: true,
        removeRight: true,
        removeBottom: true, context: context, child: Center(child: SizedBox(width: 120, height: 120, child: Material(elevation: 24.0, color: Theme.of(context).dialogBackgroundColor,type: MaterialType.card, // Change this to the widget we want to display. The external properties remain the same as the other dialogs. MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new CircularProgressIndicator(), Padding( padding: const EdgeInsets.only(top: 20), child: new Text("Loading"), ), ], ), shape: _defaultDialogShape, ), ), ), ), ); }}Copy the code

Github address of Demo

Github.com/LXD31256949…

The public,

Recently, I made a public account to learn Flutter (the possessed Winter melon). Part of it is to move some foreign articles and add some of my own understanding, part of it is my usual summary.

I hope to learn and make progress together with you in 2019!

Happy Year of the Dog!