Unverified Commit c1a118bc authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

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
parent e4ebcdf6
...@@ -51,6 +51,7 @@ class Tooltip extends StatefulWidget { ...@@ -51,6 +51,7 @@ class Tooltip extends StatefulWidget {
@required this.message, @required this.message,
this.height, this.height,
this.padding, this.padding,
this.margin,
this.verticalOffset, this.verticalOffset,
this.preferBelow, this.preferBelow,
this.excludeFromSemantics, this.excludeFromSemantics,
...@@ -75,6 +76,19 @@ class Tooltip extends StatefulWidget { ...@@ -75,6 +76,19 @@ class Tooltip extends StatefulWidget {
/// Defaults to 16.0 logical pixels in each direction. /// Defaults to 16.0 logical pixels in each direction.
final EdgeInsetsGeometry padding; 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. /// The vertical gap between the widget and the displayed tooltip.
/// ///
/// When [preferBelow] is set to true and tooltips have sufficient space to /// When [preferBelow] is set to true and tooltips have sufficient space to
...@@ -145,6 +159,7 @@ class Tooltip extends StatefulWidget { ...@@ -145,6 +159,7 @@ class Tooltip extends StatefulWidget {
properties.add(StringProperty('message', message, showName: false)); properties.add(StringProperty('message', message, showName: false));
properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(DoubleProperty('height', height, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
properties.add(DoubleProperty('vertical offset', verticalOffset, 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('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null));
properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null)); properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null));
...@@ -158,6 +173,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -158,6 +173,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
static const double _defaultVerticalOffset = 24.0; static const double _defaultVerticalOffset = 24.0;
static const bool _defaultPreferBelow = true; static const bool _defaultPreferBelow = true;
static const EdgeInsetsGeometry _defaultPadding = EdgeInsets.symmetric(horizontal: 16.0); 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 _fadeInDuration = Duration(milliseconds: 150);
static const Duration _fadeOutDuration = Duration(milliseconds: 75); static const Duration _fadeOutDuration = Duration(milliseconds: 75);
static const Duration _defaultShowDuration = Duration(milliseconds: 1500); static const Duration _defaultShowDuration = Duration(milliseconds: 1500);
...@@ -166,6 +182,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -166,6 +182,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
double height; double height;
EdgeInsetsGeometry padding; EdgeInsetsGeometry padding;
EdgeInsetsGeometry margin;
Decoration decoration; Decoration decoration;
TextStyle textStyle; TextStyle textStyle;
double verticalOffset; double verticalOffset;
...@@ -273,6 +290,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -273,6 +290,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
message: widget.message, message: widget.message,
height: height, height: height,
padding: padding, padding: padding,
margin: margin,
decoration: decoration, decoration: decoration,
textStyle: textStyle, textStyle: textStyle,
animation: CurvedAnimation( animation: CurvedAnimation(
...@@ -360,6 +378,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -360,6 +378,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
height = widget.height ?? tooltipTheme.height ?? _defaultTooltipHeight; height = widget.height ?? tooltipTheme.height ?? _defaultTooltipHeight;
padding = widget.padding ?? tooltipTheme.padding ?? _defaultPadding; padding = widget.padding ?? tooltipTheme.padding ?? _defaultPadding;
margin = widget.margin ?? tooltipTheme.margin ?? _defaultMargin;
verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset; verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset;
preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow; preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow;
excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics; excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics;
...@@ -447,6 +466,7 @@ class _TooltipOverlay extends StatelessWidget { ...@@ -447,6 +466,7 @@ class _TooltipOverlay extends StatelessWidget {
this.message, this.message,
this.height, this.height,
this.padding, this.padding,
this.margin,
this.decoration, this.decoration,
this.textStyle, this.textStyle,
this.animation, this.animation,
...@@ -458,6 +478,7 @@ class _TooltipOverlay extends StatelessWidget { ...@@ -458,6 +478,7 @@ class _TooltipOverlay extends StatelessWidget {
final String message; final String message;
final double height; final double height;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry margin;
final Decoration decoration; final Decoration decoration;
final TextStyle textStyle; final TextStyle textStyle;
final Animation<double> animation; final Animation<double> animation;
...@@ -482,6 +503,7 @@ class _TooltipOverlay extends StatelessWidget { ...@@ -482,6 +503,7 @@ class _TooltipOverlay extends StatelessWidget {
child: Container( child: Container(
decoration: decoration, decoration: decoration,
padding: padding, padding: padding,
margin: margin,
child: Center( child: Center(
widthFactor: 1.0, widthFactor: 1.0,
heightFactor: 1.0, heightFactor: 1.0,
......
...@@ -28,6 +28,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -28,6 +28,7 @@ class TooltipThemeData extends Diagnosticable {
const TooltipThemeData({ const TooltipThemeData({
this.height, this.height,
this.padding, this.padding,
this.margin,
this.verticalOffset, this.verticalOffset,
this.preferBelow, this.preferBelow,
this.excludeFromSemantics, this.excludeFromSemantics,
...@@ -43,6 +44,9 @@ class TooltipThemeData extends Diagnosticable { ...@@ -43,6 +44,9 @@ class TooltipThemeData extends Diagnosticable {
/// If provided, the amount of space by which to inset [Tooltip.child]. /// If provided, the amount of space by which to inset [Tooltip.child].
final EdgeInsetsGeometry padding; 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. /// The vertical gap between the widget and the displayed tooltip.
/// ///
/// When [preferBelow] is set to true and tooltips have sufficient space to /// When [preferBelow] is set to true and tooltips have sufficient space to
...@@ -84,6 +88,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -84,6 +88,7 @@ class TooltipThemeData extends Diagnosticable {
TooltipThemeData copyWith({ TooltipThemeData copyWith({
double height, double height,
EdgeInsetsGeometry padding, EdgeInsetsGeometry padding,
EdgeInsetsGeometry margin,
double verticalOffset, double verticalOffset,
bool preferBelow, bool preferBelow,
bool excludeFromSemantics, bool excludeFromSemantics,
...@@ -95,6 +100,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -95,6 +100,7 @@ class TooltipThemeData extends Diagnosticable {
return TooltipThemeData( return TooltipThemeData(
height: height ?? this.height, height: height ?? this.height,
padding: padding ?? this.padding, padding: padding ?? this.padding,
margin: margin ?? this.margin,
verticalOffset: verticalOffset ?? this.verticalOffset, verticalOffset: verticalOffset ?? this.verticalOffset,
preferBelow: preferBelow ?? this.preferBelow, preferBelow: preferBelow ?? this.preferBelow,
excludeFromSemantics: excludeFromSemantics ?? this.excludeFromSemantics, excludeFromSemantics: excludeFromSemantics ?? this.excludeFromSemantics,
...@@ -117,6 +123,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -117,6 +123,7 @@ class TooltipThemeData extends Diagnosticable {
return TooltipThemeData( return TooltipThemeData(
height: lerpDouble(a?.height, b?.height, t), height: lerpDouble(a?.height, b?.height, t),
padding: EdgeInsets.lerp(a?.padding, b?.padding, t), padding: EdgeInsets.lerp(a?.padding, b?.padding, t),
margin: EdgeInsets.lerp(a?.margin, b?.margin, t),
verticalOffset: lerpDouble(a?.verticalOffset, b?.verticalOffset, t), verticalOffset: lerpDouble(a?.verticalOffset, b?.verticalOffset, t),
preferBelow: t < 0.5 ? a.preferBelow: b.preferBelow, preferBelow: t < 0.5 ? a.preferBelow: b.preferBelow,
excludeFromSemantics: t < 0.5 ? a.excludeFromSemantics : b.excludeFromSemantics, excludeFromSemantics: t < 0.5 ? a.excludeFromSemantics : b.excludeFromSemantics,
...@@ -130,6 +137,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -130,6 +137,7 @@ class TooltipThemeData extends Diagnosticable {
return hashValues( return hashValues(
height, height,
padding, padding,
margin,
verticalOffset, verticalOffset,
preferBelow, preferBelow,
excludeFromSemantics, excludeFromSemantics,
...@@ -149,6 +157,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -149,6 +157,7 @@ class TooltipThemeData extends Diagnosticable {
final TooltipThemeData typedOther = other; final TooltipThemeData typedOther = other;
return typedOther.height == height return typedOther.height == height
&& typedOther.padding == padding && typedOther.padding == padding
&& typedOther.margin == margin
&& typedOther.verticalOffset == verticalOffset && typedOther.verticalOffset == verticalOffset
&& typedOther.preferBelow == preferBelow && typedOther.preferBelow == preferBelow
&& typedOther.excludeFromSemantics == excludeFromSemantics && typedOther.excludeFromSemantics == excludeFromSemantics
...@@ -163,6 +172,7 @@ class TooltipThemeData extends Diagnosticable { ...@@ -163,6 +172,7 @@ class TooltipThemeData extends Diagnosticable {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(DoubleProperty('height', height, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
properties.add(DoubleProperty('vertical offset', verticalOffset, 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('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null));
properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null)); properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null));
...@@ -208,6 +218,7 @@ class TooltipTheme extends InheritedWidget { ...@@ -208,6 +218,7 @@ class TooltipTheme extends InheritedWidget {
Key key, Key key,
double height, double height,
EdgeInsetsGeometry padding, EdgeInsetsGeometry padding,
EdgeInsetsGeometry margin,
double verticalOffset, double verticalOffset,
bool preferBelow, bool preferBelow,
bool excludeFromSemantics, bool excludeFromSemantics,
...@@ -219,6 +230,7 @@ class TooltipTheme extends InheritedWidget { ...@@ -219,6 +230,7 @@ class TooltipTheme extends InheritedWidget {
}) : data = TooltipThemeData( }) : data = TooltipThemeData(
height: height, height: height,
padding: padding, padding: padding,
margin: margin,
verticalOffset: verticalOffset, verticalOffset: verticalOffset,
preferBelow: preferBelow, preferBelow: preferBelow,
excludeFromSemantics: excludeFromSemantics, excludeFromSemantics: excludeFromSemantics,
......
...@@ -32,6 +32,13 @@ import 'feedback_tester.dart'; ...@@ -32,6 +32,13 @@ import 'feedback_tester.dart';
const String tooltipText = 'TIP'; const String tooltipText = 'TIP';
Finder _findTooltipContainer(String tooltipText) {
return find.ancestor(
of: find.text(tooltipText),
matching: find.byType(Container),
);
}
void main() { void main() {
testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
...@@ -80,8 +87,9 @@ void main() { ...@@ -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)); final Offset tipInGlobal = tip.localToGlobal(tip.size.topCenter(Offset.zero));
// The exact position of the left side depends on the font the test framework // The exact position of the left side depends on the font the test framework
// happens to pick, so we don't test that. // happens to pick, so we don't test that.
...@@ -136,7 +144,9 @@ void main() { ...@@ -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.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))); expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0)));
}, skip: isBrowser); }, skip: isBrowser);
...@@ -189,7 +199,9 @@ void main() { ...@@ -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.size.height, equals(100.0));
expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, 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)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0));
...@@ -254,7 +266,9 @@ void main() { ...@@ -254,7 +266,9 @@ void main() {
* * }- 10.0 margin * * }- 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.size.height, equals(190.0));
expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(399.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)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0));
...@@ -307,7 +321,9 @@ void main() { ...@@ -307,7 +321,9 @@ void main() {
* * }- 10.0 margin * * }- 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.size.height, equals(190.0));
expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(400.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)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0));
...@@ -361,7 +377,9 @@ void main() { ...@@ -361,7 +377,9 @@ void main() {
* * }-10.0 margin * * }-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.size.height, equals(14.0));
expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.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)).dx, equals(790.0));
...@@ -416,13 +434,73 @@ void main() { ...@@ -416,13 +434,73 @@ void main() {
* * }-10.0 margin * * }-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.size.height, equals(14.0));
expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.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)).dx, equals(790.0));
expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0));
}, skip: isBrowser); }, 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>[
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 { testWidgets('Default tooltip message textStyle - light', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
...@@ -524,8 +602,9 @@ void main() { ...@@ -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. (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) 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.height, equals(32.0));
expect(tip.size.width, equals(74.0)); expect(tip.size.width, equals(74.0));
expect(tip, paints..rrect( expect(tip, paints..rrect(
...@@ -565,8 +644,9 @@ void main() { ...@@ -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. (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) 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.height, equals(32.0));
expect(tip.size.width, equals(74.0)); expect(tip.size.width, equals(74.0));
expect(tip, paints..path( expect(tip, paints..path(
...@@ -782,14 +862,18 @@ void main() { ...@@ -782,14 +862,18 @@ void main() {
await tester.longPress(find.byType(Tooltip)); await tester.longPress(find.byType(Tooltip));
expect(find.text(tooltipText), findsOneWidget); expect(find.text(tooltipText), findsOneWidget);
expect(tester.getSize(find.text(tooltipText)), equals(const Size(42.0, 14.0))); 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)); expect(tip.size.height, equals(32.0));
await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0)); await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0));
await tester.longPress(find.byType(Tooltip)); await tester.longPress(find.byType(Tooltip));
expect(find.text(tooltipText), findsOneWidget); expect(find.text(tooltipText), findsOneWidget);
expect(tester.getSize(find.text(tooltipText)), equals(const Size(168.0, 56.0))); 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)); expect(tip.size.height, equals(56.0));
}, skip: isBrowser); }, skip: isBrowser);
...@@ -953,6 +1037,7 @@ void main() { ...@@ -953,6 +1037,7 @@ void main() {
waitDuration: Duration(seconds: 1), waitDuration: Duration(seconds: 1),
showDuration: Duration(seconds: 2), showDuration: Duration(seconds: 2),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
margin: EdgeInsets.all(5.0),
height: 100.0, height: 100.0,
excludeFromSemantics: true, excludeFromSemantics: true,
preferBelow: false, preferBelow: false,
...@@ -967,6 +1052,7 @@ void main() { ...@@ -967,6 +1052,7 @@ void main() {
'"message"', '"message"',
'height: 100.0', 'height: 100.0',
'padding: EdgeInsets.zero', 'padding: EdgeInsets.zero',
'margin: EdgeInsets.all(5.0)',
'vertical offset: 50.0', 'vertical offset: 50.0',
'position: above', 'position: above',
'semantics: excluded', 'semantics: excluded',
......
...@@ -28,6 +28,7 @@ import '../widgets/semantics_tester.dart'; ...@@ -28,6 +28,7 @@ import '../widgets/semantics_tester.dart';
// production code. // production code.
const String tooltipText = 'TIP'; const String tooltipText = 'TIP';
const double _customPaddingValue = 10.0;
void main() { void main() {
test('TooltipThemeData copyWith, ==, hashCode basics', () { test('TooltipThemeData copyWith, ==, hashCode basics', () {
...@@ -460,6 +461,118 @@ void main() { ...@@ -460,6 +461,118 @@ void main() {
expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); 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>[
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>[
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 { testWidgets('Tooltip message textStyle - ThemeData.tooltipTheme', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
...@@ -641,7 +754,7 @@ void main() { ...@@ -641,7 +754,7 @@ void main() {
final RenderBox tip = tester.renderObject(find.ancestor( final RenderBox tip = tester.renderObject(find.ancestor(
of: find.text(tooltipText), 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( final RenderBox content = tester.renderObject(find.ancestor(
of: find.text(tooltipText), of: find.text(tooltipText),
...@@ -684,7 +797,7 @@ void main() { ...@@ -684,7 +797,7 @@ void main() {
final RenderBox tip = tester.renderObject(find.ancestor( final RenderBox tip = tester.renderObject(find.ancestor(
of: find.text(tooltipText), 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( final RenderBox content = tester.renderObject(find.ancestor(
of: find.text(tooltipText), of: find.text(tooltipText),
......
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