Commit 86e5fce6 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Tooltip update can cause assert (#7338)

We were trying to update the tooltip overlay entry, but that cannot work
because the overlay entry might have already built. Instead, we keep the
old value.

Fixes #7151
parent 3176921d
......@@ -110,18 +110,6 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
_removeEntry();
}
@override
void didUpdateConfig(Tooltip oldConfig) {
super.didUpdateConfig(oldConfig);
if (_entry != null &&
(config.message != oldConfig.message ||
config.height != oldConfig.height ||
config.padding != oldConfig.padding ||
config.verticalOffset != oldConfig.verticalOffset ||
config.preferBelow != oldConfig.preferBelow))
_entry.markNeedsBuild();
}
void ensureTooltipVisible() {
if (_entry != null) {
_timer?.cancel();
......@@ -129,22 +117,24 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
_controller.forward();
return; // Already visible.
}
RenderBox box = context.findRenderObject();
Point target = box.localToGlobal(box.size.center(Point.origin));
_entry = new OverlayEntry(builder: (BuildContext context) {
return new _TooltipOverlay(
message: config.message,
height: config.height,
padding: config.padding,
animation: new CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn
),
target: target,
verticalOffset: config.verticalOffset,
preferBelow: config.preferBelow
);
});
final RenderBox box = context.findRenderObject();
final Point target = box.localToGlobal(box.size.center(Point.origin));
// We create this widget outside of the overlay entry's builder to prevent
// updated values from happening to leak into the overlay when the overlay
// rebuilds.
final Widget overlay = new _TooltipOverlay(
message: config.message,
height: config.height,
padding: config.padding,
animation: new CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn
),
target: target,
verticalOffset: config.verticalOffset,
preferBelow: config.preferBelow
);
_entry = new OverlayEntry(builder: (BuildContext context) => overlay);
Overlay.of(context, debugRequiredFor: config).insert(_entry);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
_controller.forward();
......
......@@ -473,4 +473,36 @@ void main() {
semantics.dispose();
});
testWidgets('Tooltip overlay does not update', (WidgetTester tester) async {
Widget buildApp(String text) {
return new MaterialApp(
home: new Center(
child: new Tooltip(
message: text,
child: new Container(
width: 100.0,
height: 100.0,
decoration: new BoxDecoration(
backgroundColor: Colors.green[500]
)
)
)
)
);
}
await tester.pumpWidget(buildApp(tooltipText));
await tester.longPress(find.byType(Tooltip));
expect(find.text(tooltipText), findsOneWidget);
await tester.pumpWidget(buildApp('NEW'));
expect(find.text(tooltipText), findsOneWidget);
await tester.tapAt(const Point(5.0, 5.0));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text(tooltipText), findsNothing);
await tester.longPress(find.byType(Tooltip));
expect(find.text(tooltipText), findsNothing);
});
}
......@@ -267,6 +267,26 @@ class WidgetController {
});
}
/// Dispatch a pointer down / pointer up sequence (with a delay of
/// [kLongPressTimeout] + [kPressTimeout] between the two events) at the
/// center of the given widget, assuming it is exposed. If the center of the
/// widget is not exposed, this might send events to another
/// object.
Future<Null> longPress(Finder finder, { int pointer: 1 }) {
return longPressAt(getCenter(finder), pointer: pointer);
}
/// Dispatch a pointer down / pointer up sequence at the given location with
/// a delay of [kLongPressTimeout] + [kPressTimeout] between the two events.
Future<Null> longPressAt(Point location, { int pointer: 1 }) {
return TestAsyncUtils.guard(() async {
TestGesture gesture = await startGesture(location, pointer: pointer);
await pump(kLongPressTimeout + kPressTimeout);
await gesture.up();
return null;
});
}
/// Attempts a fling gesture starting from the center of the given
/// widget, moving the given distance, reaching the given velocity.
///
......
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