From c1a118bcc3c6a776df2ffb2679ee90e0633613a5 Mon Sep 17 00:00:00 2001 From: Shi-Hao Hong Date: Sat, 27 Jul 2019 15:20:44 -0700 Subject: [PATCH] Add margins to tooltips (#36963) * Add margin parameter to tooltips * Improve tooltip tests to find the tooltip's `Container` instead of arbitrary number of parent calls --- .../flutter/lib/src/material/tooltip.dart | 22 ++++ .../lib/src/material/tooltip_theme.dart | 12 ++ .../flutter/test/material/tooltip_test.dart | 114 ++++++++++++++--- .../test/material/tooltip_theme_test.dart | 117 +++++++++++++++++- 4 files changed, 249 insertions(+), 16 deletions(-) diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart index dfdd001833..2d58c1be51 100644 --- a/packages/flutter/lib/src/material/tooltip.dart +++ b/packages/flutter/lib/src/material/tooltip.dart @@ -51,6 +51,7 @@ class Tooltip extends StatefulWidget { @required this.message, this.height, this.padding, + this.margin, this.verticalOffset, this.preferBelow, this.excludeFromSemantics, @@ -75,6 +76,19 @@ class Tooltip extends StatefulWidget { /// Defaults to 16.0 logical pixels in each direction. final EdgeInsetsGeometry padding; + /// The empty space that surrounds the tooltip. + /// + /// Defines the tooltip's outer [Container.margin]. By default, a + /// long tooltip will span the width of its window. If long enough, + /// a tooltip might also span the window's height. This property allows + /// one to define how much space the tooltip must be inset from the edges + /// of their display window. + /// + /// If this property is null, then [TooltipThemeData.margin] is used. + /// If [TooltipThemeData.margin] is also null, the default margin is + /// 0.0 logical pixels on all sides. + final EdgeInsetsGeometry margin; + /// The vertical gap between the widget and the displayed tooltip. /// /// When [preferBelow] is set to true and tooltips have sufficient space to @@ -145,6 +159,7 @@ class Tooltip extends StatefulWidget { properties.add(StringProperty('message', message, showName: false)); properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); + properties.add(DiagnosticsProperty('margin', margin, defaultValue: null)); properties.add(DoubleProperty('vertical offset', verticalOffset, defaultValue: null)); properties.add(FlagProperty('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null)); properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null)); @@ -158,6 +173,7 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { static const double _defaultVerticalOffset = 24.0; static const bool _defaultPreferBelow = true; static const EdgeInsetsGeometry _defaultPadding = EdgeInsets.symmetric(horizontal: 16.0); + static const EdgeInsetsGeometry _defaultMargin = EdgeInsets.all(0.0); static const Duration _fadeInDuration = Duration(milliseconds: 150); static const Duration _fadeOutDuration = Duration(milliseconds: 75); static const Duration _defaultShowDuration = Duration(milliseconds: 1500); @@ -166,6 +182,7 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { double height; EdgeInsetsGeometry padding; + EdgeInsetsGeometry margin; Decoration decoration; TextStyle textStyle; double verticalOffset; @@ -273,6 +290,7 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { message: widget.message, height: height, padding: padding, + margin: margin, decoration: decoration, textStyle: textStyle, animation: CurvedAnimation( @@ -360,6 +378,7 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { height = widget.height ?? tooltipTheme.height ?? _defaultTooltipHeight; padding = widget.padding ?? tooltipTheme.padding ?? _defaultPadding; + margin = widget.margin ?? tooltipTheme.margin ?? _defaultMargin; verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset; preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow; excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics; @@ -447,6 +466,7 @@ class _TooltipOverlay extends StatelessWidget { this.message, this.height, this.padding, + this.margin, this.decoration, this.textStyle, this.animation, @@ -458,6 +478,7 @@ class _TooltipOverlay extends StatelessWidget { final String message; final double height; final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry margin; final Decoration decoration; final TextStyle textStyle; final Animation animation; @@ -482,6 +503,7 @@ class _TooltipOverlay extends StatelessWidget { child: Container( decoration: decoration, padding: padding, + margin: margin, child: Center( widthFactor: 1.0, heightFactor: 1.0, diff --git a/packages/flutter/lib/src/material/tooltip_theme.dart b/packages/flutter/lib/src/material/tooltip_theme.dart index 713229f8e9..0316d33a1a 100644 --- a/packages/flutter/lib/src/material/tooltip_theme.dart +++ b/packages/flutter/lib/src/material/tooltip_theme.dart @@ -28,6 +28,7 @@ class TooltipThemeData extends Diagnosticable { const TooltipThemeData({ this.height, this.padding, + this.margin, this.verticalOffset, this.preferBelow, this.excludeFromSemantics, @@ -43,6 +44,9 @@ class TooltipThemeData extends Diagnosticable { /// If provided, the amount of space by which to inset [Tooltip.child]. final EdgeInsetsGeometry padding; + /// If provided, the amount of empty space to surround the [Tooltip]. + final EdgeInsetsGeometry margin; + /// The vertical gap between the widget and the displayed tooltip. /// /// When [preferBelow] is set to true and tooltips have sufficient space to @@ -84,6 +88,7 @@ class TooltipThemeData extends Diagnosticable { TooltipThemeData copyWith({ double height, EdgeInsetsGeometry padding, + EdgeInsetsGeometry margin, double verticalOffset, bool preferBelow, bool excludeFromSemantics, @@ -95,6 +100,7 @@ class TooltipThemeData extends Diagnosticable { return TooltipThemeData( height: height ?? this.height, padding: padding ?? this.padding, + margin: margin ?? this.margin, verticalOffset: verticalOffset ?? this.verticalOffset, preferBelow: preferBelow ?? this.preferBelow, excludeFromSemantics: excludeFromSemantics ?? this.excludeFromSemantics, @@ -117,6 +123,7 @@ class TooltipThemeData extends Diagnosticable { return TooltipThemeData( height: lerpDouble(a?.height, b?.height, t), padding: EdgeInsets.lerp(a?.padding, b?.padding, t), + margin: EdgeInsets.lerp(a?.margin, b?.margin, t), verticalOffset: lerpDouble(a?.verticalOffset, b?.verticalOffset, t), preferBelow: t < 0.5 ? a.preferBelow: b.preferBelow, excludeFromSemantics: t < 0.5 ? a.excludeFromSemantics : b.excludeFromSemantics, @@ -130,6 +137,7 @@ class TooltipThemeData extends Diagnosticable { return hashValues( height, padding, + margin, verticalOffset, preferBelow, excludeFromSemantics, @@ -149,6 +157,7 @@ class TooltipThemeData extends Diagnosticable { final TooltipThemeData typedOther = other; return typedOther.height == height && typedOther.padding == padding + && typedOther.margin == margin && typedOther.verticalOffset == verticalOffset && typedOther.preferBelow == preferBelow && typedOther.excludeFromSemantics == excludeFromSemantics @@ -163,6 +172,7 @@ class TooltipThemeData extends Diagnosticable { super.debugFillProperties(properties); properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); + properties.add(DiagnosticsProperty('margin', margin, defaultValue: null)); properties.add(DoubleProperty('vertical offset', verticalOffset, defaultValue: null)); properties.add(FlagProperty('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null)); properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null)); @@ -208,6 +218,7 @@ class TooltipTheme extends InheritedWidget { Key key, double height, EdgeInsetsGeometry padding, + EdgeInsetsGeometry margin, double verticalOffset, bool preferBelow, bool excludeFromSemantics, @@ -219,6 +230,7 @@ class TooltipTheme extends InheritedWidget { }) : data = TooltipThemeData( height: height, padding: padding, + margin: margin, verticalOffset: verticalOffset, preferBelow: preferBelow, excludeFromSemantics: excludeFromSemantics, diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 50f58d5405..bcb86ee703 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -32,6 +32,13 @@ import 'feedback_tester.dart'; const String tooltipText = 'TIP'; +Finder _findTooltipContainer(String tooltipText) { + return find.ancestor( + of: find.text(tooltipText), + matching: find.byType(Container), + ); +} + void main() { testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -80,8 +87,9 @@ void main() { * * *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent; - + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); final Offset tipInGlobal = tip.localToGlobal(tip.size.topCenter(Offset.zero)); // The exact position of the left side depends on the font the test framework // happens to pick, so we don't test that. @@ -136,7 +144,9 @@ void main() { * * *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(24.0)); // 14.0 height + 5.0 padding * 2 (top, bottom) expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0))); }, skip: isBrowser); @@ -189,7 +199,9 @@ void main() { * * *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(100.0)); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(100.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); @@ -254,7 +266,9 @@ void main() { * * }- 10.0 margin *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(190.0)); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(399.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); @@ -307,7 +321,9 @@ void main() { * * }- 10.0 margin *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(190.0)); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(400.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); @@ -361,7 +377,9 @@ void main() { * * }-10.0 margin *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(14.0)); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dx, equals(790.0)); @@ -416,13 +434,73 @@ void main() { * * }-10.0 margin *********************/ - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(14.0)); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dx, equals(790.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }, skip: isBrowser); + testWidgets('Custom tooltip margin', (WidgetTester tester) async { + const double _customMarginValue = 10.0; + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + initialEntries: [ + OverlayEntry( + builder: (BuildContext context) { + return Tooltip( + key: key, + message: tooltipText, + padding: const EdgeInsets.all(0.0), + margin: const EdgeInsets.all(_customMarginValue), + child: Container( + width: 0.0, + height: 0.0, + ), + ); + }, + ), + ], + ), + ), + ); + (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file. + await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) + + final Offset topLeftTipInGlobal = tester.getTopLeft( + _findTooltipContainer(tooltipText), + ); + final Offset topLeftTooltipContentInGlobal = tester.getTopLeft(find.text(tooltipText)); + expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customMarginValue); + expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customMarginValue); + + final Offset topRightTipInGlobal = tester.getTopRight( + _findTooltipContainer(tooltipText), + ); + final Offset topRightTooltipContentInGlobal = tester.getTopRight(find.text(tooltipText)); + expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customMarginValue); + expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customMarginValue); + + final Offset bottomLeftTipInGlobal = tester.getBottomLeft( + _findTooltipContainer(tooltipText), + ); + final Offset bottomLeftTooltipContentInGlobal = tester.getBottomLeft(find.text(tooltipText)); + expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customMarginValue); + expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customMarginValue); + + final Offset bottomRightTipInGlobal = tester.getBottomRight( + _findTooltipContainer(tooltipText), + ); + final Offset bottomRightTooltipContentInGlobal = tester.getBottomRight(find.text(tooltipText)); + expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customMarginValue); + expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customMarginValue); + }); + testWidgets('Default tooltip message textStyle - light', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -524,8 +602,9 @@ void main() { (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file. await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent; - + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(32.0)); expect(tip.size.width, equals(74.0)); expect(tip, paints..rrect( @@ -565,8 +644,9 @@ void main() { (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file. await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) - final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent; - + final RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(32.0)); expect(tip.size.width, equals(74.0)); expect(tip, paints..path( @@ -782,14 +862,18 @@ void main() { await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)), equals(const Size(42.0, 14.0))); - RenderBox tip = tester.renderObject(find.text(tooltipText)).parent; + RenderBox tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(32.0)); await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0)); await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)), equals(const Size(168.0, 56.0))); - tip = tester.renderObject(find.text(tooltipText)).parent; + tip = tester.renderObject( + _findTooltipContainer(tooltipText), + ); expect(tip.size.height, equals(56.0)); }, skip: isBrowser); @@ -953,6 +1037,7 @@ void main() { waitDuration: Duration(seconds: 1), showDuration: Duration(seconds: 2), padding: EdgeInsets.zero, + margin: EdgeInsets.all(5.0), height: 100.0, excludeFromSemantics: true, preferBelow: false, @@ -967,6 +1052,7 @@ void main() { '"message"', 'height: 100.0', 'padding: EdgeInsets.zero', + 'margin: EdgeInsets.all(5.0)', 'vertical offset: 50.0', 'position: above', 'semantics: excluded', diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index 722b6760c7..3625ef63ed 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -28,6 +28,7 @@ import '../widgets/semantics_tester.dart'; // production code. const String tooltipText = 'TIP'; +const double _customPaddingValue = 10.0; void main() { test('TooltipThemeData copyWith, ==, hashCode basics', () { @@ -460,6 +461,118 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); + testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + initialEntries: [ + OverlayEntry( + builder: (BuildContext context) { + return Theme( + data: ThemeData( + tooltipTheme: const TooltipThemeData( + padding: EdgeInsets.all(0.0), + margin: EdgeInsets.all(_customPaddingValue), + ), + ), + child: Tooltip( + key: key, + message: tooltipText, + child: Container( + width: 0.0, + height: 0.0, + ), + ), + ); + }, + ), + ], + ), + ), + ); + (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file. + await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) + + final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent; + final RenderBox tooltipContent = tester.renderObject(find.text(tooltipText)); + + final Offset topLeftTipInGlobal = tip.localToGlobal(tip.size.topLeft(Offset.zero)); + final Offset topLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topLeft(Offset.zero)); + expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customPaddingValue); + expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customPaddingValue); + + final Offset topRightTipInGlobal = tip.localToGlobal(tip.size.topRight(Offset.zero)); + final Offset topRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topRight(Offset.zero)); + expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customPaddingValue); + expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customPaddingValue); + + final Offset bottomLeftTipInGlobal = tip.localToGlobal(tip.size.bottomLeft(Offset.zero)); + final Offset bottomLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomLeft(Offset.zero)); + expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customPaddingValue); + expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customPaddingValue); + + final Offset bottomRightTipInGlobal = tip.localToGlobal(tip.size.bottomRight(Offset.zero)); + final Offset bottomRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomRight(Offset.zero)); + expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customPaddingValue); + expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); + }); + + testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + initialEntries: [ + OverlayEntry( + builder: (BuildContext context) { + return TooltipTheme( + padding: const EdgeInsets.all(0.0), + margin: const EdgeInsets.all(_customPaddingValue), + child: Tooltip( + key: key, + message: tooltipText, + child: Container( + width: 0.0, + height: 0.0, + ), + ), + ); + }, + ), + ], + ), + ), + ); + (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file. + await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) + + final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent; + final RenderBox tooltipContent = tester.renderObject(find.text(tooltipText)); + + final Offset topLeftTipInGlobal = tip.localToGlobal(tip.size.topLeft(Offset.zero)); + final Offset topLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topLeft(Offset.zero)); + expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customPaddingValue); + expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customPaddingValue); + + final Offset topRightTipInGlobal = tip.localToGlobal(tip.size.topRight(Offset.zero)); + final Offset topRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topRight(Offset.zero)); + expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customPaddingValue); + expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customPaddingValue); + + final Offset bottomLeftTipInGlobal = tip.localToGlobal(tip.size.bottomLeft(Offset.zero)); + final Offset bottomLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomLeft(Offset.zero)); + expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customPaddingValue); + expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customPaddingValue); + + final Offset bottomRightTipInGlobal = tip.localToGlobal(tip.size.bottomRight(Offset.zero)); + final Offset bottomRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomRight(Offset.zero)); + expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customPaddingValue); + expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); + }); + testWidgets('Tooltip message textStyle - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -641,7 +754,7 @@ void main() { final RenderBox tip = tester.renderObject(find.ancestor( of: find.text(tooltipText), - matching: find.byType(Padding), + matching: find.byType(Padding).first, // select [Tooltip.padding] instead of [Tooltip.margin] )); final RenderBox content = tester.renderObject(find.ancestor( of: find.text(tooltipText), @@ -684,7 +797,7 @@ void main() { final RenderBox tip = tester.renderObject(find.ancestor( of: find.text(tooltipText), - matching: find.byType(Padding), + matching: find.byType(Padding).first, // select [Tooltip.padding] instead of [Tooltip.margin] )); final RenderBox content = tester.renderObject(find.ancestor( of: find.text(tooltipText),