Commit 1abc7c9e authored by Ian Hickson's avatar Ian Hickson

Clarify the "needs an Overlay" assert.

Fixes https://github.com/flutter/flutter/issues/2436
parent 4f97e0ca
......@@ -182,6 +182,7 @@ class _DropDownRoute<T> extends PopupRoute<_DropDownRouteResult<T>> {
ModalPosition getPosition(BuildContext context) {
RenderBox overlayBox = Overlay.of(context).context.findRenderObject();
assert(overlayBox != null); // can't be null; routes get inserted by Navigator which has its own Overlay
Size overlaySize = overlayBox.size;
RelativeRect menuRect = new RelativeRect.fromSize(rect, overlaySize);
return new ModalPosition(
......
......@@ -46,6 +46,7 @@ class Tooltip extends StatefulComponent {
assert(preferBelow != null);
assert(fadeDuration != null);
assert(showDuration != null);
assert(child != null);
}
final String message;
......@@ -150,7 +151,7 @@ class _TooltipState extends State<Tooltip> {
preferBelow: config.preferBelow
);
});
Overlay.of(context).insert(_entry);
Overlay.of(context, debugRequiredFor: config).insert(_entry);
}
_timer?.cancel();
if (_controller.status != AnimationStatus.completed) {
......@@ -175,7 +176,7 @@ class _TooltipState extends State<Tooltip> {
}
Widget build(BuildContext context) {
assert(Overlay.of(context) != null);
assert(Overlay.of(context, debugRequiredFor: config) != null);
return new GestureDetector(
behavior: HitTestBehavior.opaque,
onLongPress: showTooltip,
......
......@@ -234,7 +234,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> {
_activeCount += 1;
});
return new _DragAvatar<T>(
overlay: Overlay.of(context),
overlay: Overlay.of(context, debugRequiredFor: config),
data: config.data,
initialPosition: position,
dragStartPoint: dragStartPoint,
......@@ -249,6 +249,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> {
}
Widget build(BuildContext context) {
assert(Overlay.of(context, debugRequiredFor: config) != null);
final bool canDrag = config.maxSimultaneousDrags == null ||
_activeCount < config.maxSimultaneousDrags;
final bool showChild = _activeCount == 0 || config.childWhenDragging == null;
......
......@@ -137,6 +137,9 @@ class Mimic extends StatelessComponent {
}
/// A widget that can be copied by a [Mimic].
///
/// This widget's State, [MimicableState], contains an API for initiating the
/// mimic operation.
class Mimicable extends StatefulComponent {
Mimicable({ Key key, this.child }) : super(key: key);
......@@ -193,8 +196,7 @@ class MimicableState extends State<Mimicable> {
/// had when the mimicking process started and (2) the child will be
/// placed in the enclosing overlay.
MimicOverlayEntry liftToOverlay() {
OverlayState overlay = Overlay.of(context);
assert(overlay != null); // You need an overlay to lift into.
OverlayState overlay = Overlay.of(context, debugRequiredFor: config);
MimicOverlayEntry entry = new MimicOverlayEntry._(startMimic());
overlay.insert(entry._overlayEntry);
return entry;
......
......@@ -71,7 +71,32 @@ class Overlay extends StatefulComponent {
final List<OverlayEntry> initialEntries;
/// The state from the closest instance of this class that encloses the given context.
static OverlayState of(BuildContext context) => context.ancestorStateOfType(const TypeMatcher<OverlayState>());
///
/// In checked mode, if the [debugRequiredFor] argument is provided then this
/// function will assert that an overlay was found and will throw an exception
/// if not. The exception attempts to explain that the calling [Widget] (the
/// one given by the [debugRequiredFor] argument) needs an [Overlay] to be
/// present to function.
static OverlayState of(BuildContext context, { Widget debugRequiredFor }) {
OverlayState result = context.ancestorStateOfType(const TypeMatcher<OverlayState>());
assert(() {
if (debugRequiredFor != null && result == null) {
String additional = context.widget != debugRequiredFor
? '\nThe context from which that widget was searching for an overlay was:\n $context'
: '';
throw new WidgetError(
'No Overlay widget found.\n'
'${debugRequiredFor.runtimeType} widgets require an Overlay widget ancestor for correct operation.\n'
'The most common way to add an Overlay to an application is to include a MaterialApp or Navigator widget in the runApp() call.\n'
'The specific widget that failed to find an overlay was:\n'
' $debugRequiredFor'
'$additional'
);
}
return true;
});
return result;
}
OverlayState createState() => new OverlayState();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment