Reputation: 20406
How to show AlertDialog always on top of anything on the screen?
Code:
import 'package:flutter/material.dart';
class CountriesField extends StatefulWidget {
@override
_CountriesFieldState createState() => _CountriesFieldState();
}
class _CountriesFieldState extends State<CountriesField> {
final FocusNode _focusNode = FocusNode();
OverlayEntry _overlayEntry;
final LayerLink _layerLink = LayerLink();
@override
void initState() {
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
} else {
// this._overlayEntry.remove();
}
});
}
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
return OverlayEntry(
builder: (context) => Positioned(
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, size.height + 5.0),
child: Material(
elevation: 4.0,
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: <Widget>[
ListTile(
title: Text('Syria'),
onTap: () {
print('Syria Tapped');
},
),
ListTile(
title: Text('Lebanon'),
onTap: () {
print('Lebanon Tapped');
},
)
],
),
),
),
));
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: Material(
child: TextFormField(
focusNode: this._focusNode,
decoration: InputDecoration(labelText: 'Country'),
),
),
);
}
}
class FormPage extends StatefulWidget {
@override
_FormPageState createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Material(elevation: 4.0, child: CountriesField()),
RaisedButton(
child: Text('Help dialog'),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Help"),
content: Text("This should show on top of any overlay"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
},
)
],
),
);
}
}
Upvotes: 8
Views: 9304
Reputation: 5956
This isn't really a "fix", but a potential workaround for this is to basically not use Overlays and rely on a top level Stack.
If you are using Positioned in your Overlay anyway, putting your widget in a top level Stack doesn't interfere with things like Dialogs (and you potentially have more control over which areas of your app show the overlay).
Example:
class StackOverlayState extends State<StackOverlay> {
bool _showOverlay = true; // This could also easily be a list of widgets
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(
child: Scaffold(
body: /// etc..
),
),
if (_showOverlay)
MyOverlayWidget(),
],
);
}
}
I was using Overlays, and switching to just using a Stack instead seems to have caused no issues and required no code changes in the Overlay widget itself, but YMMV.
Upvotes: 1
Reputation: 36333
There is no easy way to make dialogs appear on top of overlays. Depends on your use case, you can either convert both to Overlay
, or convert both to Dialog
.
This is an example of converting both to dialogs, using showDialog
method:
You don't have to return an AlertDialog
widget when showing a dialog, for example, here I'm returning a Container
with white filling, and contains a ListView
for the "Menu A" dialog in the back.
When using showDialog
, you get automatic features such as dimming the background and click anywhere outside to dismiss. If you don't want these or any other dialog things, and if you cannot find a way to disable them easily, you can always go the other way around and convert both to Overlay
instead.
For overlays, whichever gets inserted latest, is displayed on top.
Upvotes: 2