flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.19k stars 27.26k forks source link

Avoid stacked scrims #137109

Open Craftplacer opened 11 months ago

Craftplacer commented 11 months ago

Is there an existing issue for this?

Use case

In cases where the application might display dialogs upon dialogs, the scrim (darkening background) of the dialogs stack on each other, causing a more and more dark background until it is black. This is clearly visually unpleasing -- putting too much emphasis on a dialog.

image

Working around this is not feasible since not every dialog or view is designed to have some kind of nesting.

Proposal

Solution 1

Introduce logic to the navigator to only show the top-most non-opaque route.

For example we have this navigation stack:

The ideal solution would be if the navigator only showed this stack in practice:

Closing a dialog would (cross-)fade to the previous one.

Solution 2

Telegram Desktop (which is heavily inspired by Material Design), moves the scrim between dialogs, fading the previous dialog behind the scrim. It seems like TG Desktop applies another scrim on the surface of the previous dialog.

Screencast from 2023-10-24 01-17-57.webm

dam-ease commented 11 months ago

Hi @Craftplacer. Can you please provide a completed and minimal reproducible code sample that doesn’t include 3rd party plugins or complex production code showing the current behaviour?

Craftplacer commented 11 months ago

Here's the requested example:

Code sample

```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: FilledButton( child: Text('Show dialogs'), onPressed: showDialogs, ), ), ); } void showDialogs() { for (int i = 0; i < 5; i++) { showDialog( context: context, builder: (_) { return AlertDialog( title: Text("Important Dialog!"), icon: Icon(Icons.warning), content: Text("This is dialog number ${i + 1}"), actions: [ _PopButton("OK"), ], ); }, ); } } } class _PopButton extends StatelessWidget { final String text; const _PopButton(this.text); @override Widget build(BuildContext context) { return TextButton( child: Text(text), onPressed: () => Navigator.of(context).pop(), ); } } ```

dam-ease commented 11 months ago

Thanks for sharing this. I see the use case you are describing now still appears on both master and stable channels.

https://github.com/flutter/flutter/assets/53122008/3aff1aba-d70e-4bb1-b4ef-22ccd5b73ed4

HansMuller commented 11 months ago

This is a reasonable feature request. I've labeled it P3 because we don't have near term plans to pursue a solution. Happy to review a PR of course.