sgon00
sgon00

Reputation: 5827

How to make entire screen inactive (darken) under a popup widget in flutter (similar to showDialog)?

I have an "add" floating action button in Scaffold. When clicking the "add" floating action button, it will create two more floating action buttons above the original floating action button so that the user can choose which floating action button to click.

When the two more floating action buttons are active/popup, I want the entire screen to go blur/dark and inactive, similar to the effect to call showDialog(). So that only the three floating action buttons are active and all other screen parts are inactive and dark/blur.

And finally by clicking the inactive area, the two floating action buttons will be dismissed.

Upvotes: 1

Views: 2601

Answers (2)

sgon00
sgon00

Reputation: 5827

I found two ways to achieve this.

With PopupRoute

I read flutter framework code and found out showDialog is actually using PopupRoute. Basically, this will create a new route and make the previous routepage inactive.

The simplest code is as follows:

class MyPopupRoute extends PopupRoute<void> {
  @override
  Color get barrierColor => Colors.black54;

  @override
  bool get barrierDismissible => true;
  @override
  String get barrierLabel => "Close";

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => MyPopupPage();

  @override
  Duration get transitionDuration => const Duration(milliseconds: 300);
}

where MyPopupPage is the new popup widget.

If you want animations, you can override the method buildTransitions method. Simply check the API doc for more detail.

With Overlay

Thank @01leo very much for providing this way. The Flutter Challenge: Feature Discovery video has detail explanation on how to use it. Basically, just use Overlay.of(context).insert(overlayEntry); and the overlay is like a hidden stack on the top of the current page built-in.

At the time I am writing this answer, the code provided by the video author is not working in the latest fluter (dart 2). You have to wrap the overlay insert in a Timer such as Timer.run(() { Overlay.of(context).insert(calendarOverlay);}); to workaround the problem and make the code run.

By my findings, the reason why the author needs an async function call for overlay insert is because it couples the creation of overlay and the normal widget in a stateful widget. And when the state changes, the overlay insert will be called before building the child's widget and overlay needs to know the child's position but the child's widget is not created yet. If you don't want to async call overlay insert, you can simply decouple the creation of overlay and the corresponding normal widget. In such a way, you can simply call overlay insert normally. But with this sync way, you may not be able to find the normal widget position easily though. (Btw, I use the word "normal widget" here, but it's not very correct. I haven't found a proper English word for it.)

Upvotes: 4

leodriesch
leodriesch

Reputation: 5780

I can't provide any code, but showDialog() and similar methods use the Overlay, integrated in Scaffold. It can be accessed by using Overlay.of(context). It essentially is a Stack around the whole Scaffold and you can insert items on top of everything.

For a more in-depth look into the Overlay and code examples I recommend watching this Flutter Challenge: Feature Discovery

Upvotes: 2

Related Questions