mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
commit
abb17ea93f
@ -73,7 +73,8 @@ class TabViewDemo extends StatelessComponent {
|
||||
children: <Widget>[
|
||||
new IconButton(
|
||||
icon: "navigation/arrow_back",
|
||||
onPressed: () { _handleArrowButtonPress(context, -1); }
|
||||
onPressed: () { _handleArrowButtonPress(context, -1); },
|
||||
tooltip: 'Back'
|
||||
),
|
||||
new Row(
|
||||
children: _iconNames.map((String name) => _buildTabIndicator(context, name)).toList(),
|
||||
@ -81,7 +82,8 @@ class TabViewDemo extends StatelessComponent {
|
||||
),
|
||||
new IconButton(
|
||||
icon: "navigation/arrow_forward",
|
||||
onPressed: () { _handleArrowButtonPress(context, 1); }
|
||||
onPressed: () { _handleArrowButtonPress(context, 1); },
|
||||
tooltip: 'Forward'
|
||||
)
|
||||
],
|
||||
justifyContent: FlexJustifyContent.spaceBetween
|
||||
|
||||
@ -154,11 +154,13 @@ class StockHomeState extends State<StockHome> {
|
||||
right: <Widget>[
|
||||
new IconButton(
|
||||
icon: "action/search",
|
||||
onPressed: _handleSearchBegin
|
||||
onPressed: _handleSearchBegin,
|
||||
tooltip: 'Search'
|
||||
),
|
||||
new IconButton(
|
||||
icon: "navigation/more_vert",
|
||||
onPressed: _handleMenuShow
|
||||
onPressed: _handleMenuShow,
|
||||
tooltip: 'Show menu'
|
||||
)
|
||||
],
|
||||
tabBar: new TabBar<StockHomeTab>(
|
||||
@ -229,7 +231,8 @@ class StockHomeState extends State<StockHome> {
|
||||
left: new IconButton(
|
||||
icon: 'navigation/arrow_back',
|
||||
colorFilter: new ColorFilter.mode(Theme.of(context).accentColor, ui.TransferMode.srcATop),
|
||||
onPressed: _handleSearchEnd
|
||||
onPressed: _handleSearchEnd,
|
||||
tooltip: 'Back'
|
||||
),
|
||||
center: new Input(
|
||||
key: searchFieldKey,
|
||||
|
||||
@ -53,6 +53,7 @@ export 'src/material/time_picker.dart';
|
||||
export 'src/material/time_picker_dialog.dart';
|
||||
export 'src/material/toggleable.dart';
|
||||
export 'src/material/tool_bar.dart';
|
||||
export 'src/material/tooltip.dart';
|
||||
export 'src/material/typography.dart';
|
||||
|
||||
export 'widgets.dart';
|
||||
|
||||
@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'icon.dart';
|
||||
import 'icon_theme_data.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'tooltip.dart';
|
||||
|
||||
class IconButton extends StatelessComponent {
|
||||
const IconButton({
|
||||
@ -14,16 +15,18 @@ class IconButton extends StatelessComponent {
|
||||
this.icon,
|
||||
this.color,
|
||||
this.colorFilter,
|
||||
this.onPressed
|
||||
this.onPressed,
|
||||
this.tooltip
|
||||
}) : super(key: key);
|
||||
|
||||
final String icon;
|
||||
final IconThemeColor color;
|
||||
final ColorFilter colorFilter;
|
||||
final VoidCallback onPressed;
|
||||
final String tooltip;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new InkResponse(
|
||||
Widget result = new InkResponse(
|
||||
onTap: onPressed,
|
||||
child: new Padding(
|
||||
padding: const EdgeDims.all(8.0),
|
||||
@ -34,10 +37,23 @@ class IconButton extends StatelessComponent {
|
||||
)
|
||||
)
|
||||
);
|
||||
if (tooltip != null) {
|
||||
result = new Tooltip(
|
||||
message: tooltip,
|
||||
child: result
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void debugFillDescription(List<String> description) {
|
||||
super.debugFillDescription(description);
|
||||
description.add('$icon');
|
||||
if (onPressed == null)
|
||||
description.add('disabled');
|
||||
if (color != null)
|
||||
description.add('$color');
|
||||
if (tooltip != null)
|
||||
description.add('tooltip: "$tooltip"');
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,14 +331,16 @@ class ScaffoldState extends State<Scaffold> {
|
||||
if (config.drawer != null) {
|
||||
left = new IconButton(
|
||||
icon: 'navigation/menu',
|
||||
onPressed: openDrawer
|
||||
onPressed: openDrawer,
|
||||
tooltip: 'Open navigation menu' // TODO(ianh): Figure out how to localize this string
|
||||
);
|
||||
} else {
|
||||
_shouldShowBackArrow ??= Navigator.canPop(context);
|
||||
if (_shouldShowBackArrow) {
|
||||
left = new IconButton(
|
||||
icon: 'navigation/arrow_back',
|
||||
onPressed: () => Navigator.pop(context)
|
||||
onPressed: () => Navigator.pop(context),
|
||||
tooltip: 'Back' // TODO(ianh): Figure out how to localize this string
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
292
packages/flutter/lib/src/material/tooltip.dart
Normal file
292
packages/flutter/lib/src/material/tooltip.dart
Normal file
@ -0,0 +1,292 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
const double _kDefaultTooltipBorderRadius = 2.0;
|
||||
const double _kDefaultTooltipHeight = 32.0;
|
||||
const EdgeDims _kDefaultTooltipPadding = const EdgeDims.symmetric(horizontal: 16.0);
|
||||
const double _kDefaultVerticalTooltipOffset = 24.0;
|
||||
const EdgeDims _kDefaultTooltipScreenEdgeMargin = const EdgeDims.all(10.0);
|
||||
const Duration _kDefaultTooltipFadeDuration = const Duration(milliseconds: 200);
|
||||
const Duration _kDefaultTooltipShowDuration = const Duration(seconds: 2);
|
||||
|
||||
class Tooltip extends StatefulComponent {
|
||||
Tooltip({
|
||||
Key key,
|
||||
this.message,
|
||||
this.backgroundColor,
|
||||
this.textColor,
|
||||
this.style,
|
||||
this.opacity: 0.9,
|
||||
this.borderRadius: _kDefaultTooltipBorderRadius,
|
||||
this.height: _kDefaultTooltipHeight,
|
||||
this.padding: _kDefaultTooltipPadding,
|
||||
this.verticalOffset: _kDefaultVerticalTooltipOffset,
|
||||
this.screenEdgeMargin: _kDefaultTooltipScreenEdgeMargin,
|
||||
this.preferBelow: true,
|
||||
this.fadeDuration: _kDefaultTooltipFadeDuration,
|
||||
this.showDuration: _kDefaultTooltipShowDuration,
|
||||
this.child
|
||||
}) : super(key: key) {
|
||||
assert(message != null);
|
||||
assert(opacity != null);
|
||||
assert(borderRadius != null);
|
||||
assert(height != null);
|
||||
assert(padding != null);
|
||||
assert(verticalOffset != null);
|
||||
assert(screenEdgeMargin != null);
|
||||
assert(preferBelow != null);
|
||||
assert(fadeDuration != null);
|
||||
assert(showDuration != null);
|
||||
}
|
||||
|
||||
final String message;
|
||||
final Color backgroundColor;
|
||||
final Color textColor;
|
||||
final TextStyle style;
|
||||
final double opacity;
|
||||
final double borderRadius;
|
||||
final double height;
|
||||
final EdgeDims padding;
|
||||
final double verticalOffset;
|
||||
final EdgeDims screenEdgeMargin;
|
||||
final bool preferBelow;
|
||||
final Duration fadeDuration;
|
||||
final Duration showDuration;
|
||||
final Widget child;
|
||||
|
||||
_TooltipState createState() => new _TooltipState();
|
||||
}
|
||||
|
||||
class _TooltipState extends State<Tooltip> {
|
||||
|
||||
Performance _performance;
|
||||
OverlayEntry _entry;
|
||||
Timer _timer;
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
_performance = new Performance(duration: config.fadeDuration)
|
||||
..addStatusListener((PerformanceStatus status) {
|
||||
switch (status) {
|
||||
case PerformanceStatus.completed:
|
||||
assert(_entry != null);
|
||||
assert(_timer == null);
|
||||
resetShowTimer();
|
||||
break;
|
||||
case PerformanceStatus.dismissed:
|
||||
assert(_entry != null);
|
||||
assert(_timer == null);
|
||||
_entry.remove();
|
||||
_entry = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void didUpdateConfig(Tooltip oldConfig) {
|
||||
super.didUpdateConfig(oldConfig);
|
||||
if (config.fadeDuration != oldConfig.fadeDuration)
|
||||
_performance.duration = config.fadeDuration;
|
||||
if (_entry != null &&
|
||||
(config.message != oldConfig.message ||
|
||||
config.backgroundColor != oldConfig.backgroundColor ||
|
||||
config.style != oldConfig.style ||
|
||||
config.textColor != oldConfig.textColor ||
|
||||
config.borderRadius != oldConfig.borderRadius ||
|
||||
config.height != oldConfig.height ||
|
||||
config.padding != oldConfig.padding ||
|
||||
config.opacity != oldConfig.opacity ||
|
||||
config.verticalOffset != oldConfig.verticalOffset ||
|
||||
config.screenEdgeMargin != oldConfig.screenEdgeMargin ||
|
||||
config.preferBelow != oldConfig.preferBelow))
|
||||
_entry.markNeedsBuild();
|
||||
}
|
||||
|
||||
void resetShowTimer() {
|
||||
assert(_performance.status == PerformanceStatus.completed);
|
||||
assert(_entry != null);
|
||||
_timer = new Timer(config.showDuration, hideTooltip);
|
||||
}
|
||||
|
||||
void showTooltip() {
|
||||
if (_entry == null) {
|
||||
RenderBox box = context.findRenderObject();
|
||||
Point target = box.localToGlobal(box.size.center(Point.origin));
|
||||
_entry = new OverlayEntry(builder: (BuildContext context) {
|
||||
TextStyle textStyle = (config.style ?? Theme.of(context).text.body1).copyWith(color: config.textColor ?? Colors.white);
|
||||
return new _TooltipOverlay(
|
||||
message: config.message,
|
||||
backgroundColor: config.backgroundColor ?? Colors.grey[700],
|
||||
style: textStyle,
|
||||
borderRadius: config.borderRadius,
|
||||
height: config.height,
|
||||
padding: config.padding,
|
||||
opacity: config.opacity,
|
||||
performance: _performance,
|
||||
target: target,
|
||||
verticalOffset: config.verticalOffset,
|
||||
screenEdgeMargin: config.screenEdgeMargin,
|
||||
preferBelow: config.preferBelow
|
||||
);
|
||||
});
|
||||
Overlay.of(context).insert(_entry);
|
||||
}
|
||||
_timer?.cancel();
|
||||
if (_performance.status != PerformanceStatus.completed) {
|
||||
_timer = null;
|
||||
_performance.forward();
|
||||
} else {
|
||||
resetShowTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void hideTooltip() {
|
||||
assert(_entry != null);
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
_performance.reverse();
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
if (_entry != null)
|
||||
hideTooltip();
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
assert(Overlay.of(context) != null);
|
||||
return new GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onLongPress: showTooltip,
|
||||
child: config.child
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TooltipPositionDelegate extends OneChildLayoutDelegate {
|
||||
_TooltipPositionDelegate({
|
||||
this.target,
|
||||
this.verticalOffset,
|
||||
this.screenEdgeMargin,
|
||||
this.preferBelow
|
||||
});
|
||||
final Point target;
|
||||
final double verticalOffset;
|
||||
final EdgeDims screenEdgeMargin;
|
||||
final bool preferBelow;
|
||||
|
||||
BoxConstraints getConstraintsForChild(BoxConstraints constraints) => constraints.loosen();
|
||||
|
||||
Offset getPositionForChild(Size size, Size childSize) {
|
||||
// VERTICAL DIRECTION
|
||||
final bool fitsBelow = target.y + verticalOffset + childSize.height <= size.height - screenEdgeMargin.bottom;
|
||||
final bool fitsAbove = target.y - verticalOffset - childSize.height >= screenEdgeMargin.top;
|
||||
final bool tooltipBelow = preferBelow ? fitsBelow || !fitsAbove : !(fitsAbove || !fitsBelow);
|
||||
double y;
|
||||
if (tooltipBelow)
|
||||
y = math.min(target.y + verticalOffset, size.height - screenEdgeMargin.bottom);
|
||||
else
|
||||
y = math.max(target.y - verticalOffset - childSize.height, screenEdgeMargin.top);
|
||||
// HORIZONTAL DIRECTION
|
||||
double normalizedTargetX = target.x.clamp(screenEdgeMargin.left, size.width - screenEdgeMargin.right);
|
||||
double x;
|
||||
if (normalizedTargetX < screenEdgeMargin.left + childSize.width / 2.0) {
|
||||
x = screenEdgeMargin.left;
|
||||
} else if (normalizedTargetX > size.width - screenEdgeMargin.right - childSize.width / 2.0) {
|
||||
x = size.width - screenEdgeMargin.right - childSize.width;
|
||||
} else {
|
||||
x = normalizedTargetX + childSize.width / 2.0;
|
||||
}
|
||||
return new Offset(x, y);
|
||||
}
|
||||
|
||||
bool shouldRelayout(_TooltipPositionDelegate oldDelegate) {
|
||||
return target != target
|
||||
|| verticalOffset != verticalOffset
|
||||
|| screenEdgeMargin != screenEdgeMargin
|
||||
|| preferBelow != preferBelow;
|
||||
}
|
||||
}
|
||||
|
||||
class _TooltipOverlay extends StatelessComponent {
|
||||
_TooltipOverlay({
|
||||
Key key,
|
||||
this.message,
|
||||
this.backgroundColor,
|
||||
this.style,
|
||||
this.borderRadius,
|
||||
this.height,
|
||||
this.padding,
|
||||
this.opacity,
|
||||
this.performance,
|
||||
this.target,
|
||||
this.verticalOffset,
|
||||
this.screenEdgeMargin,
|
||||
this.preferBelow
|
||||
}) : super(key: key);
|
||||
|
||||
final String message;
|
||||
final Color backgroundColor;
|
||||
final TextStyle style;
|
||||
final double opacity;
|
||||
final double borderRadius;
|
||||
final double height;
|
||||
final EdgeDims padding;
|
||||
final PerformanceView performance;
|
||||
final Point target;
|
||||
final double verticalOffset;
|
||||
final EdgeDims screenEdgeMargin;
|
||||
final bool preferBelow;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
bottom: 0.0,
|
||||
child: new IgnorePointer(
|
||||
child: new CustomOneChildLayout(
|
||||
delegate: new _TooltipPositionDelegate(
|
||||
target: target,
|
||||
verticalOffset: verticalOffset,
|
||||
screenEdgeMargin: screenEdgeMargin,
|
||||
preferBelow: preferBelow
|
||||
),
|
||||
child: new FadeTransition(
|
||||
performance: performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease),
|
||||
child: new Opacity(
|
||||
opacity: opacity,
|
||||
child: new Container(
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: backgroundColor,
|
||||
borderRadius: borderRadius
|
||||
),
|
||||
height: height,
|
||||
padding: padding,
|
||||
child: new Center(
|
||||
widthFactor: 1.0,
|
||||
child: new Text(message, style: style)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,8 @@
|
||||
import 'box.dart';
|
||||
import 'object.dart';
|
||||
|
||||
// For OneChildLayoutDelegate and RenderCustomOneChildLayoutBox, see shifted_box.dart
|
||||
|
||||
class MultiChildLayoutParentData extends ContainerBoxParentDataMixin<RenderBox> {
|
||||
/// An object representing the identity of this child.
|
||||
Object id;
|
||||
|
||||
@ -14,6 +14,9 @@ import 'object.dart';
|
||||
/// container, this class has no width and height members. To determine the
|
||||
/// width or height of the rectangle, convert it to a [Rect] using [toRect()]
|
||||
/// (passing the container's own Rect), and then examine that object.
|
||||
///
|
||||
/// If you create the RelativeRect with null values, the methods on
|
||||
/// RelativeRect will not work usefully (or at all).
|
||||
class RelativeRect {
|
||||
|
||||
/// Creates a RelativeRect with the given values.
|
||||
@ -125,7 +128,7 @@ class RelativeRect {
|
||||
|
||||
int get hashCode => hashValues(left, top, right, bottom);
|
||||
|
||||
String toString() => "RelativeRect.fromLTRB(${left.toStringAsFixed(1)}, ${top.toStringAsFixed(1)}, ${right.toStringAsFixed(1)}, ${bottom.toStringAsFixed(1)})";
|
||||
String toString() => "RelativeRect.fromLTRB(${left?.toStringAsFixed(1)}, ${top?.toStringAsFixed(1)}, ${right?.toStringAsFixed(1)}, ${bottom?.toStringAsFixed(1)})";
|
||||
}
|
||||
|
||||
/// Parent data for use with [RenderStack]
|
||||
@ -155,10 +158,10 @@ class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
|
||||
/// Get or set the current values in terms of a RelativeRect object.
|
||||
RelativeRect get rect => new RelativeRect.fromLTRB(left, top, right, bottom);
|
||||
void set rect(RelativeRect value) {
|
||||
left = value.left;
|
||||
top = value.top;
|
||||
right = value.right;
|
||||
bottom = value.bottom;
|
||||
left = value.left;
|
||||
}
|
||||
|
||||
void merge(StackParentData other) {
|
||||
@ -185,7 +188,24 @@ class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
|
||||
/// children in the stack.
|
||||
bool get isPositioned => top != null || right != null || bottom != null || left != null || width != null || height != null;
|
||||
|
||||
String toString() => '${super.toString()}; top=$top; right=$right; bottom=$bottom; left=$left; width=$width; height=$height';
|
||||
String toString() {
|
||||
List<String> values = <String>[];
|
||||
if (top != null)
|
||||
values.add('top=$top');
|
||||
if (right != null)
|
||||
values.add('right=$right');
|
||||
if (bottom != null)
|
||||
values.add('bottom=$bottom');
|
||||
if (left != null)
|
||||
values.add('left=$left');
|
||||
if (width != null)
|
||||
values.add('width=$width');
|
||||
if (height != null)
|
||||
values.add('height=$height');
|
||||
if (values.length == null)
|
||||
return 'all null';
|
||||
return values.join('; ');
|
||||
}
|
||||
}
|
||||
|
||||
abstract class RenderStackBase extends RenderBox
|
||||
|
||||
357
packages/flutter/test/widget/tooltip_test.dart
Normal file
357
packages/flutter/test/widget/tooltip_test.dart
Normal file
@ -0,0 +1,357 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('Does tooltip end up in the right place - top left', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 0.0,
|
||||
top: 0.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 20.0,
|
||||
padding: const EdgeDims.all(5.0),
|
||||
verticalOffset: 20.0,
|
||||
screenEdgeMargin: const EdgeDims.all(10.0),
|
||||
preferBelow: false,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
/********************* 800x600 screen
|
||||
*o * y=0
|
||||
*| * }- 20.0 vertical offset, of which 10.0 is in the screen edge margin
|
||||
*+----+ * \- (5.0 padding in height)
|
||||
*| | * |- 20 height
|
||||
*+----+ * /- (5.0 padding in height)
|
||||
* *
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent.parent.parent.parent.parent;
|
||||
expect(tip.size.height, equals(20.0)); // 10.0 height + 5.0 padding * 2 (top, bottom)
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)), equals(const Point(10.0, 20.0)));
|
||||
});
|
||||
});
|
||||
|
||||
test('Does tooltip end up in the right place - center prefer above fits', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 400.0,
|
||||
top: 300.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 100.0,
|
||||
padding: const EdgeDims.all(0.0),
|
||||
verticalOffset: 100.0,
|
||||
screenEdgeMargin: const EdgeDims.all(100.0),
|
||||
preferBelow: false,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
/********************* 800x600 screen
|
||||
* ___ * }-100.0 margin
|
||||
* |___| * }-100.0 height
|
||||
* | * }-100.0 vertical offset
|
||||
* o * y=300.0
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent;
|
||||
expect(tip.size.height, equals(100.0));
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)).y, equals(100.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).y, equals(200.0));
|
||||
});
|
||||
});
|
||||
|
||||
test('Does tooltip end up in the right place - center prefer above does not fit', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 400.0,
|
||||
top: 299.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 100.0,
|
||||
padding: const EdgeDims.all(0.0),
|
||||
verticalOffset: 100.0,
|
||||
screenEdgeMargin: const EdgeDims.all(100.0),
|
||||
preferBelow: false,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
// we try to put it here but it doesn't fit:
|
||||
/********************* 800x600 screen
|
||||
* ___ * }-100.0 margin
|
||||
* |___| * }-100.0 height (starts at y=99.0)
|
||||
* | * }-100.0 vertical offset
|
||||
* o * y=299.0
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*********************/
|
||||
|
||||
// so we put it here:
|
||||
/********************* 800x600 screen
|
||||
* *
|
||||
* *
|
||||
* o * y=299.0
|
||||
* _|_ * }-100.0 vertical offset
|
||||
* |___| * }-100.0 height
|
||||
* * }-100.0 margin
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent;
|
||||
expect(tip.size.height, equals(100.0));
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)).y, equals(399.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).y, equals(499.0));
|
||||
});
|
||||
});
|
||||
|
||||
test('Does tooltip end up in the right place - center prefer below fits', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 400.0,
|
||||
top: 300.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 100.0,
|
||||
padding: const EdgeDims.all(0.0),
|
||||
verticalOffset: 100.0,
|
||||
screenEdgeMargin: const EdgeDims.all(100.0),
|
||||
preferBelow: true,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
/********************* 800x600 screen
|
||||
* *
|
||||
* *
|
||||
* o * y=300.0
|
||||
* _|_ * }-100.0 vertical offset
|
||||
* |___| * }-100.0 height
|
||||
* * }-100.0 margin
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent;
|
||||
expect(tip.size.height, equals(100.0));
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)).y, equals(400.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).y, equals(500.0));
|
||||
});
|
||||
});
|
||||
|
||||
test('Does tooltip end up in the right place - way off to the right', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 1600.0,
|
||||
top: 300.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 10.0,
|
||||
padding: const EdgeDims.all(0.0),
|
||||
verticalOffset: 10.0,
|
||||
screenEdgeMargin: const EdgeDims.all(10.0),
|
||||
preferBelow: true,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
/********************* 800x600 screen
|
||||
* *
|
||||
* *
|
||||
* * y=300.0; target --> o
|
||||
* ___| * }-10.0 vertical offset
|
||||
* |___| * }-10.0 height
|
||||
* *
|
||||
* * }-10.0 margin
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent;
|
||||
expect(tip.size.height, equals(10.0));
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)).y, equals(310.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).x, equals(790.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).y, equals(320.0));
|
||||
});
|
||||
});
|
||||
|
||||
test('Does tooltip end up in the right place - near the edge', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey key = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
new OverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
return new Stack(
|
||||
children: <Widget>[
|
||||
new Positioned(
|
||||
left: 780.0,
|
||||
top: 300.0,
|
||||
child: new Tooltip(
|
||||
key: key,
|
||||
message: 'TIP',
|
||||
height: 10.0,
|
||||
padding: const EdgeDims.all(0.0),
|
||||
verticalOffset: 10.0,
|
||||
screenEdgeMargin: const EdgeDims.all(10.0),
|
||||
preferBelow: true,
|
||||
fadeDuration: const Duration(seconds: 1),
|
||||
showDuration: const Duration(seconds: 2),
|
||||
child: new Container(
|
||||
width: 0.0,
|
||||
height: 0.0
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
key.currentState.showTooltip();
|
||||
tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
|
||||
|
||||
/********************* 800x600 screen
|
||||
* *
|
||||
* *
|
||||
* o * y=300.0
|
||||
* __| * }-10.0 vertical offset
|
||||
* |___| * }-10.0 height
|
||||
* *
|
||||
* * }-10.0 margin
|
||||
*********************/
|
||||
|
||||
RenderBox tip = tester.findText('TIP').renderObject.parent;
|
||||
expect(tip.size.height, equals(10.0));
|
||||
expect(tip.localToGlobal(tip.size.topLeft(Point.origin)).y, equals(310.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).x, equals(790.0));
|
||||
expect(tip.localToGlobal(tip.size.bottomRight(Point.origin)).y, equals(320.0));
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user