Clarify the "needs an Overlay" assert.
Fixes https://github.com/flutter/flutter/issues/2436
This commit is contained in:
parent
4f97e0ca7c
commit
1abc7c9ebe
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user