I am trying to create a custom Dialog that will be as short as its content up until this content is too high, at which point it should be scrollable.

Here is what I'm starting with:

showDialog(
  context: context,
  useSafeArea: true,
  barrierDismissible: true,
  useRootNavigator: false,
  builder: (context) => Dialog(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(20),
    ),
    elevation: 3,
    backgroundColor: Theme.of(context).colorScheme.surface,
    child: Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Text(lorem(paragraphs: 1)),
          SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
            },
            child: Text('OK'),
          ),
        ],
      ),
    ),
  ),
);

This gives me the following result:

enter image description here

Now if I add more text to make it taller, the height of the dialog adapts:

enter image description here

If we go even further, at some point, we go into overflow:

enter image description here

So I wrap my text in a SingleChildScrollView but that's not enough to fix the overflow, so I wrap the SingleChildScrollView into an Expanded:

Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Expanded(
        child: SingleChildScrollView(
          child: Text(lorem(paragraphs: 30)),
        ),
      ),
      SizedBox(height: 20),
      ElevatedButton(
        onPressed: () {
          Navigator.pop(context);
        },
        child: Text('OK'),
      ),
    ],
)

This time the text scrolls as expected, and the dialog uses all the vertical space it can but not more:

enter image description here

But now if I reduce the text size again the that it's shorter than the available space, the dialog still takes up all the vertical space and leaves a gap between the text and the button:

enter image description here

And obviously, that's not what I want. Any idea how I can make this work without calling onto MediaQuery witchcraft?


Solution 1: Harry

I suggest changing the position of SingleChildScrollView to on top of Column and I hope that should work fine.

Something similar as below:

              height: 200,
              width: 300,
              child: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
//Your children's column code 
]


Solution 2: Jimenez

You can use Column and Flexible.

void showCustomDialog(BuildContext context, String message) async {
    await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: Container(
            width: double.maxFinite,
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: [                      
                  Text("Description 1",
                      style: TextStyle(fontWeight: FontWeight.bold)),
                  SizedBox(height: 8),
                  Flexible(
                    child: SingleChildScrollView(
                      child: Text(message),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                       Navigator.of(context).pop();
                    },
                    child: Text("OK"),
                  )
                ]),
          ),
        );
      },
    );
  }