Skip to content

Instantly share code, notes, and snippets.

@micimize
Created April 28, 2020 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micimize/61505c392f877bd0b2df9103d5a2bb97 to your computer and use it in GitHub Desktop.
Save micimize/61505c392f877bd0b2df9103d5a2bb97 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showOverlay = true;
@override
Widget build(BuildContext context) {
final blankArea = Container(
height: 300,
color: Colors.black,
);
return Scaffold(
appBar: AppBar(
title: Text('overlay demo'),
),
body: ListView(
children: <Widget>[
blankArea,
blankArea,
OverlayContainer(
offset: Offset(300, 50),
show: showOverlay,
overlay: Container(
height: 40, width: 100, color: Colors.red, child: Text("wow")),
child: ListTile(
title: Text("wowee I've got an overlay"),
leading: IconButton(
onPressed: () => setState(
() => showOverlay = !showOverlay,
),
tooltip: 'toggle overlay',
icon: Icon(
showOverlay ? Icons.expand_less : Icons.expand_more,
)),
),
),
blankArea,
blankArea,
blankArea,
blankArea
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(
() => showOverlay = !showOverlay,
),
tooltip: 'toggle overlay',
child: Icon(
showOverlay ? Icons.expand_less : Icons.expand_more,
),
),
);
}
}
class OverlayContainer extends StatefulWidget {
/// The child to render in the regular document flow (defaults to Container())
final Widget child;
/// The widget to render inside the [OverlayEntry].
final Widget overlay;
/// Offset to apply to the [CompositedTransformFollower]
final Offset offset;
/// Controlling whether the overlay is current showing or not.
///
/// Note: if you have an animated component you'll probably need to leave this `true`
/// and wrap your floating widget in a `Visible`:
/// ```dart
/// Visibility(
/// visible: isVisible,
/// maintainSize: true,
/// maintainState: true,
/// maintainAnimation: true,
/// // ...
/// ```
final bool show;
OverlayContainer({
Key key,
@required this.overlay,
this.child,
this.offset,
this.show = true,
}) : super(key: key);
@override
_OverlayContainerState createState() => _OverlayContainerState();
}
class _OverlayContainerState extends State<OverlayContainer>
with WidgetsBindingObserver {
OverlayEntry _overlayEntry;
final LayerLink _layerLink = LayerLink();
@override
void initState() {
super.initState();
if (widget.show) {
_show();
}
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeMetrics() {
// We would want to re render the overlay if any metrics
// ever change.
if (widget.show) {
_show();
} else {
_hide();
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// We would want to re render the overlay if any of the dependencies
// ever change.
if (widget.show) {
_show();
} else {
_hide();
}
}
@override
void didUpdateWidget(OverlayContainer oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.show) {
_show();
} else {
_hide();
}
}
@override
void dispose() {
if (widget.show) {
_hide();
}
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
void _show() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (_overlayEntry == null) {
_overlayEntry = _buildOverlayEntry();
Overlay.of(context).insert(_overlayEntry);
} else {
_overlayEntry.markNeedsBuild();
}
});
}
void _hide() {
if (_overlayEntry != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_overlayEntry.remove();
_overlayEntry = null;
});
}
}
@override
Widget build(BuildContext context) {
// Listen to changes in media query such as when a device orientation changes
// or when the keyboard is toggled.
// MediaQuery.of(context);
return CompositedTransformTarget(
link: this._layerLink,
child: widget.child ?? Container(),
);
}
OverlayEntry _buildOverlayEntry() {
return OverlayEntry(
opaque: false,
builder: (context) {
return FittedBox(
fit: BoxFit.cover,
child: CompositedTransformFollower(
offset: widget.offset,
link: this._layerLink,
//showWhenUnlinked: false,
child: FittedBox(
fit: BoxFit.none,
child: widget.overlay,
),
),
);
},
);
}
}
@micimize
Copy link
Author

micimize commented May 4, 2020

@hermitdave let's continue discussion from MustansirZia/overlay_container#6 here –

When overlay is visible, it prevents the underlying scrollviewer from accepting any scroll events. Did you have the same issue ? if so is there any workaround ?

If you mean the exact area around the overlay, that's just a matter of normal gesture handling. Adding an IgnorePointer solved it for me:

            overlay: IgnorePointer(child: Container(
                height: 40, width: 100, color: Colors.red, child: Text("wow"))),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment