In Flutter, the overlay lets you print visual elements on top of other widgets by inserting them into the overlay's stack. You insert a widget into the overlay using an OverlayEntry and you use Positioned and AnimatedPositioned to choose where the entry is positioned within the overlay.
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.
The Overlay widget uses a custom stack implementation, which is very similar to the Stack widget. The main use case of Overlay is related to navigation and being able to insert widgets on top of the pages in an app. To simply display a stack of widgets, consider using Stack instead.
Maybe a more optimal way exists, but as an option this is an example with two pages, local navigator and Overlay.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: WillPopScope(
onWillPop: () async => !await _navigatorKey.currentState.maybePop(),
child: LayoutBuilder(
builder: (context, constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) => _insertOverlay(context));
return Navigator(
key: _navigatorKey,
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/page2':
return MaterialPageRoute(builder: (_) => Page2());
default:
return MaterialPageRoute(builder: (_) => Page1(_navigatorKey));
}
},
);
},
),
),
);
}
void _insertOverlay(BuildContext context) {
return Overlay.of(context).insert(
OverlayEntry(builder: (context) {
final size = MediaQuery.of(context).size;
print(size.width);
return Positioned(
width: 56,
height: 56,
top: size.height - 72,
left: size.width - 72,
child: Material(
color: Colors.transparent,
child: GestureDetector(
onTap: () => print('ON TAP OVERLAY!'),
child: Container(
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.redAccent),
),
),
),
);
}),
);
}
}
class Page1 extends StatelessWidget {
final GlobalKey<NavigatorState> navigatorKey;
Page1(this.navigatorKey);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[200],
appBar: AppBar(title: Text('Page1')),
body: Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('go to Page2'),
onPressed: () => navigatorKey.currentState.pushNamed('/page2'),
),
),
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow[200],
appBar: AppBar(title: Text('back to Page1')),
body: Container(
alignment: Alignment.center,
child: Text('Page 2'),
),
);
}
}
After reading the comments, find github-repo-link
flutterflutter-layout
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Stack( <-- using stack
children: [
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
OverlayView(),<-- my overlay widget
],
),
);
}
}
class OverlayView extends StatelessWidget {
const OverlayView({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>( <--- IMP , using ValueListenableBuilder for showing/removing overlay
valueListenable: Loader.appLoader.loaderShowingNotifier,
builder: (context, value, child) {
if (value) {
return yourOverLayWidget(); <-- your awesome overlay
} else {
return Container();
}
},
);
}
class Loader {
static final Loader appLoader = Loader(); <-- singleton
ValueNotifier<bool> loaderShowingNotifier = ValueNotifier(false);
ValueNotifier<String> loaderTextNotifier = ValueNotifier('error message');
void showLoader() { <-- using to show from anywhere
loaderShowingNotifier.value = true;
}
void hideLoader() { <-- using to hide from anywhere
loaderShowingNotifier.value = false;
}
void setText({String errorMessage}) { <-- using to change error message from anywhere
loaderTextNotifier.value = errorMessage;
}
void setImage() { <-- DIY
// same as that of setText //
}
}
I'm showing it, on boilerplate code of increment method to show the loader
void _incrementCounter() async {
Loader.appLoader.showLoader(); <-- show loder
Loader.appLoader.setText(errorMessage: 'this is custom error message');<-- set custom message
await Future.delayed(Duration(seconds: 5)); <-- im hiding it after 5 sec
Loader.appLoader.hideLoader(); <-- do whatever you want
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Offset _offset = Offset.zero;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: LoginPage(),
builder: (context, child) {
return Stack(
children: [
child!,
Positioned(
left: _offset.dx,
top: _offset.dy,
child: GestureDetector(
onPanUpdate: (d) => setState(() => _offset += Offset(d.delta.dx, d.delta.dy)),
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.black,
child: Icon(Icons.add),
),
),
),
],
);
},
);
}
}
LoginPage
:
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('LoginPage')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => HomePage())),
child: Text('Page2'),
),
),
);
}
}
HomePage
:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HomePage')),
body: FlutterLogo(size: 300),
);
}
}
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