67 lines
1.7 KiB
Dart
67 lines
1.7 KiB
Dart
/// Skips building while another route covers this one, then rebuilds on pop.
|
|
library;
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// Shared observer — register on [MaterialApp.navigatorObservers].
|
|
final RouteObserver<ModalRoute<void>> appRouteObserver =
|
|
RouteObserver<ModalRoute<void>>();
|
|
|
|
/// Builds via [builder] only when this route is not covered by a pushed page.
|
|
///
|
|
/// Uses [ModalRoute.isCurrent] so nested dialogs above a bottom sheet do not
|
|
/// falsely "uncover" the page when the dialog pops (sheet still open).
|
|
class SkipBuildWhenCovered extends StatefulWidget {
|
|
const SkipBuildWhenCovered({
|
|
super.key,
|
|
required this.builder,
|
|
this.placeholder = const SizedBox.expand(),
|
|
});
|
|
|
|
final WidgetBuilder builder;
|
|
final Widget placeholder;
|
|
|
|
@override
|
|
State<SkipBuildWhenCovered> createState() => _SkipBuildWhenCoveredState();
|
|
}
|
|
|
|
class _SkipBuildWhenCoveredState extends State<SkipBuildWhenCovered>
|
|
with RouteAware {
|
|
var _covered = false;
|
|
|
|
void _syncCovered() {
|
|
final route = ModalRoute.of(context);
|
|
final covered = route != null && !route.isCurrent;
|
|
if (covered == _covered) return;
|
|
setState(() => _covered = covered);
|
|
}
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
final route = ModalRoute.of(context);
|
|
if (route is PageRoute) {
|
|
appRouteObserver.subscribe(this, route);
|
|
}
|
|
_syncCovered();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
appRouteObserver.unsubscribe(this);
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
void didPushNext() => _syncCovered();
|
|
|
|
@override
|
|
void didPopNext() => _syncCovered();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (_covered) return widget.placeholder;
|
|
return widget.builder(context);
|
|
}
|
|
}
|