SimpleCloudNotifier/flutter/lib/components/bottom_fab/anchored_overlay.dart

116 lines
2.6 KiB
Dart

import 'package:flutter/material.dart';
class AnchoredOverlay extends StatelessWidget {
final bool showOverlay;
final Widget Function(BuildContext, Offset anchor) overlayBuilder;
final Widget child;
const AnchoredOverlay({
super.key,
required this.showOverlay,
required this.overlayBuilder,
required this.child,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
return OverlayBuilder(
showOverlay: showOverlay,
overlayBuilder: (BuildContext overlayContext) {
RenderBox box = context.findRenderObject() as RenderBox;
final center = box.size.center(box.localToGlobal(const Offset(0.0, 0.0)));
return overlayBuilder(overlayContext, center);
},
child: child,
);
});
}
}
class OverlayBuilder extends StatefulWidget {
final bool showOverlay;
final Widget Function(BuildContext) overlayBuilder;
final Widget child;
const OverlayBuilder({
super.key,
this.showOverlay = false,
required this.overlayBuilder,
required this.child,
});
@override
State<OverlayBuilder> createState() => _OverlayBuilderState();
}
class _OverlayBuilderState extends State<OverlayBuilder> {
OverlayEntry? overlayEntry;
@override
void initState() {
super.initState();
if (widget.showOverlay) {
WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay());
}
}
@override
void didUpdateWidget(OverlayBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void reassemble() {
super.reassemble();
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void dispose() {
if (isShowingOverlay()) {
hideOverlay();
}
super.dispose();
}
bool isShowingOverlay() => overlayEntry != null;
void showOverlay() {
overlayEntry = OverlayEntry(
builder: widget.overlayBuilder,
);
addToOverlay(overlayEntry!);
}
void addToOverlay(OverlayEntry entry) async {
print('addToOverlay');
Overlay.of(context).insert(entry);
}
void hideOverlay() {
print('hideOverlay');
if (overlayEntry != null) {
overlayEntry!.remove();
overlayEntry = null;
}
}
void syncWidgetAndOverlay() {
if (isShowingOverlay() && !widget.showOverlay) {
hideOverlay();
} else if (!isShowingOverlay() && widget.showOverlay) {
showOverlay();
}
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}