Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
abb17ea9
Commit
abb17ea9
authored
Jan 14, 2016
by
Ian Hickson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1237 from Hixie/tooltips
Tooltips
parents
28d4e52a
24cab899
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
707 additions
and
12 deletions
+707
-12
page_selector_demo.dart
examples/material_gallery/lib/demo/page_selector_demo.dart
+4
-2
stock_home.dart
examples/stocks/lib/stock_home.dart
+6
-3
material.dart
packages/flutter/lib/material.dart
+1
-0
icon_button.dart
packages/flutter/lib/src/material/icon_button.dart
+18
-2
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+4
-2
tooltip.dart
packages/flutter/lib/src/material/tooltip.dart
+292
-0
custom_layout.dart
packages/flutter/lib/src/rendering/custom_layout.dart
+2
-0
stack.dart
packages/flutter/lib/src/rendering/stack.dart
+23
-3
tooltip_test.dart
packages/flutter/test/widget/tooltip_test.dart
+357
-0
No files found.
examples/material_gallery/lib/demo/page_selector_demo.dart
View file @
abb17ea9
...
...
@@ -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
...
...
examples/stocks/lib/stock_home.dart
View file @
abb17ea9
...
...
@@ -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
,
...
...
packages/flutter/lib/material.dart
View file @
abb17ea9
...
...
@@ -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'
;
packages/flutter/lib/src/material/icon_button.dart
View file @
abb17ea9
...
...
@@ -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
"'
);
}
}
packages/flutter/lib/src/material/scaffold.dart
View file @
abb17ea9
...
...
@@ -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
);
}
}
...
...
packages/flutter/lib/src/material/tooltip.dart
0 → 100644
View file @
abb17ea9
// 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
)
)
)
)
)
)
)
);
}
}
packages/flutter/lib/src/rendering/custom_layout.dart
View file @
abb17ea9
...
...
@@ -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
;
...
...
packages/flutter/lib/src/rendering/stack.dart
View file @
abb17ea9
...
...
@@ -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
...
...
packages/flutter/test/widget/tooltip_test.dart
0 → 100644
View file @
abb17ea9
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment