I'm creating an overlay onClick of a button, that is working fine from below code, but I want to close the overlay by clicking outside of it.
Reference code:
For creating overlay I'm using OverlayEntry
Setting the overlay position by using offset which is available when taped on any of the six buttons.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: GesturePositionDetector(),
);
}
}
class GesturePositionDetector extends StatelessWidget {
OverlayState overlayState;
OverlayEntry _overlayEntry;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_getButtons([1, 2, 3], context),
_getButtons([4, 5, 6], context),
_getButtons([7, 8, 9], context)
],
)),
);
}
Widget _getButtons(List<int> labels, BuildContext context) {
var listOfButtons = List<Widget>();
labels.forEach((int label) {
listOfButtons.add(_getButtonView('Button $label', context, label));
});
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: listOfButtons);
}
Widget _getButtonView(String label, BuildContext context, int index) {
return GestureDetector(
child: Container(
height: 50,
width: 150,
margin : EdgeInsets.fromLTRB(15, 25, 15, 20),
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Center(
child: Text(
label,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
onTapDown: (details) {
onTap(details, context, index);
},
);
}
onTap(TapDownDetails details, context, int index) {
var size = MediaQuery.of(context).size;
var offset = details.globalPosition;
_overlayEntry?.remove();
overlayState = Overlay.of(context);
_overlayEntry = new OverlayEntry(
builder: (BuildContext context) => Positioned(
left: offset.dx + 300 >= size.width ? offset.dx - 300 : offset.dx,
top: offset.dy + 200 >= size.height ? offset.dy - 200 : offset.dy,
child: Material(
color: Colors.transparent,
child: Container(
width: 300,
height: 200,
child: Container(
decoration: BoxDecoration(
color: Colors.white70,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5.0,
),
]),
margin: EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.fromLTRB(16, 10, 16, 10),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
direction: Axis.vertical,
spacing: 10,
children: <Widget>[
Text(
'Main Text',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
Text('sub text 1'),
Text('sub text 2'),
Text('sub text 3'),
Text('sub text 4')
],
))),
)));
overlayState.insert(_overlayEntry);
}
}
You'll learn more about ready-to-use public functions that Flutter provides to show dialogs and menus. These functions show route-aware overlays, so you dismiss them by pressing the system back button.
Use Stack() and have a container that will fill the entire screen behind your reaction bar. Use GestureDetector to detect the tap on that container. I'm wrapping the entire screen/body with GestureDetector and used onTapDown to get where the tap has been happened.
The Overlay in Flutter makes it easy to create visual elements on top of other widgets by adding them to the Overlay's stack. OverlayEntry is used to insert a widget into the Overlay, then Positioned or AnimatedPositioned is used to determine where it will enter within the Overlay.
Wrap the body with Gesture detector, On tap of body the tap event will fire, in tap event method close the overlay as shown in below code
Code:
body: GestureDetector(
onTap: (){
_overlayEntry?.remove();
},
child : Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With