“This is the 23rd day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Custom dialog

Let’s start with an example

class ExamResultDialog extends Dialog{...@override
  Widget build(BuildContext context) {
    return newExamResultDialogContent(entity, listener); }}class ExamResultDialogContent extends StatefulWidget{...@override
  State<StatefulWidget> createState() {
    ...
    return_ExamResultDialogContent(); }... }class _ExamResultDialogContent extends State<ExamResultDialogContent>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: Center(
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.all(Radius.circular(20)),
          ),
          width: 752,
          height: 426, child: ... .// Content section),),); }}Copy the code

As you can see from above, the Dialog is inherited first, then the widget in its build function, and the rest is similar to a normal widget.

But a few caveats:

  • The Scaffold layer needs to be wrapped otherwise all default styles will fail.
  • With that Scaffold the background is opaque and needs to be set to transparent again.
  • Dialog is full-screen by default, so you need to limit the size of the content with Container and Center the content with a Center wrap. You can also add decoration to the Container to create a pop-up background

Dialog that resizes dynamically

In development, we often encounter such dialogs, whose contents vary greatly, so the size of the dialogs should also change. However, for the sake of aesthetics, the size of the dialogs should not change when there are too many contents, but the contents can be scrolled to view.

Let’s implement the dialog step by step

Text Content is scrollable

This also solves the problem of incomplete Text display.

Let’s use the simplest dialog with only Text, so the first step is to figure out how to make the Text scroll if there is too much Text.

The answer is to use SingleChildScrollView, which has only one child, and its purpose is to scroll through it if the child is too big.

Code:

SingleChildScrollView(
   child: Text(
      widget.msg,
      style:TextStyle(color: Color(0xff919294), fontSize: 18),),Copy the code

But there is a problem here, although scrolling, but the Text display is not complete, phenomenon is when the Text content is too much, the last line can not be seen, and the second to last line can only be half displayed.

This is not a problem with SingleChildScrollView. After testing, when using Text alone on a blank page, the height is not limited, such a situation will still occur, even if the lower part of Text is still blank, and the following Text is still not displayed.

Note: This condition occurs on Flutter Web, occurs on Chrome, is not tested on Android or ios, and may be a Web-specific problem

After a lot of trial and error, we found that setting overflow: Textoverflow. ellipsis for Text works, and the Text should display in its entirety.

Overflow is what to do with words when they are not displayed. Ellipsis is ellipsis, shape is visible, and so on. It’s not clear why setting Ellipsis works but setting Visible doesn’t.

Ellipsis can solve the problem of using Text alone. If you use SingleChildScrollView to reach the scrolling effect, Text will display only one line…

My solution here is to set the maxLines of Text: 100, where 100 is just a large number, could be 1000, as long as the content is fully displayed.

This solution is not ideal, but it is the only solution I can think of for now. Final code:

SingleChildScrollView(
   child: Text(
      widget.msg,
      overflow: TextOverflow.ellipsis,
      maxLines: 100,
      style:TextStyle(color: Color(0xff919294), fontSize: 18),),Copy the code

The window resizes dynamically and limits the maximum height

Here we use LimitedBox to implement the height limit, directly on the code:

SizedBox(
    width: 400,
    child: Container(
      child: Stack(
        children: [
          Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                child: Text(
                  "Notice",
                  style: TextStyle(color: Color(0xff212223), fontSize: 24),
                ),
                width: double.infinity,
                alignment: Alignment.center,
                margin: EdgeInsets.only(top: 10, bottom: 20),
              ),
              LimitedBox(
                maxHeight: 400,
                child: SingleChildScrollView(
                  child: Text(
                    widget.msg,
                    overflow: TextOverflow.ellipsis,
                    maxLines: 100,
                    style:
                        TextStyle(color: Color(0xff919294), fontSize: 18),
                  ),
                  padding: EdgeInsets.only(left: 20, right: 20),
                ),
              ),
              Padding(padding: EdgeInsets.all(10))
            ],
          ),
          GestureDetector(
            child: Container(
              child: Image.asset(
                R.assetsAlertClose,
                width: 20,
                height: 20,
              ),
              padding: EdgeInsets.all(10),
              alignment: Alignment.topRight,
            ),
            onTap: () {
              Navigator.of(context).pop();
            },
          )
        ],
      ),
      decoration: ShapeDecoration(
        color: Colors.white,
        shape: RoundedRectangleBorder(
          side: BorderSide(color: Colors.transparent),
          borderRadius: BorderRadius.all(
            Radius.circular(13),),),),));Copy the code

The outermost layer is a SizedBox. The purpose is to set the width of the window. This is fixed, while the height of the window is dynamic. Then I ran into the first problem. At first I used LimitedBox on the second layer as follows:

SizedBox(
    width: 400,
    child: LimitedBox(
       maxHeight: 400,
    child: Container(
     ...
Copy the code

However, no matter how big the Container content is, the Container height (even if there is no content in it) will always be 400, and we expect the Container height to vary with the content, with a maximum height limit of 400

After trying to place LimitedBox in the inner layer of Container, the specific reason is still unknown. There have been many problems with the nesting of Flutter UI.

The end result is the same as above, with only a LimitedBox layer on the outer layer of the content section to limit the maximum height, which is dynamic and has a maximum limit.

Note also that in Column I set mainAxisSize: mainAxisSize. Min because Column is fully expanded vertically by default, the height cannot change dynamically, so I set it to be displayed vertically based on the content.

Due to the nesting of various UIs and default values in Flutter, there is still some work to be done to dynamically resize components. There are some pitfalls to be aware of.