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
ee802bfe
Commit
ee802bfe
authored
Nov 18, 2015
by
Ian Hickson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Model ink splashes more physically
parent
366d078d
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
923 additions
and
494 deletions
+923
-494
animated_value.dart
packages/flutter/lib/src/animation/animated_value.dart
+23
-10
colors.dart
packages/flutter/lib/src/material/colors.dart
+4
-2
drawer_item.dart
packages/flutter/lib/src/material/drawer_item.dart
+23
-21
flat_button.dart
packages/flutter/lib/src/material/flat_button.dart
+21
-11
floating_action_button.dart
...ages/flutter/lib/src/material/floating_action_button.dart
+15
-13
icon_button.dart
packages/flutter/lib/src/material/icon_button.dart
+2
-4
ink_well.dart
packages/flutter/lib/src/material/ink_well.dart
+130
-268
material.dart
packages/flutter/lib/src/material/material.dart
+391
-27
material_button.dart
packages/flutter/lib/src/material/material_button.dart
+39
-20
raised_button.dart
packages/flutter/lib/src/material/raised_button.dart
+33
-13
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+4
-1
snack_bar.dart
packages/flutter/lib/src/material/snack_bar.dart
+24
-11
tabs.dart
packages/flutter/lib/src/material/tabs.dart
+12
-14
theme_data.dart
packages/flutter/lib/src/material/theme_data.dart
+10
-12
tool_bar.dart
packages/flutter/lib/src/material/tool_bar.dart
+46
-35
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+42
-6
notification_listener.dart
packages/flutter/lib/src/widgets/notification_listener.dart
+55
-0
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+10
-0
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
scheduler_test.dart
packages/unit/test/animation/scheduler_test.dart
+4
-0
date_picker_test.dart
packages/unit/test/widget/date_picker_test.dart
+12
-10
heroes_test.dart
packages/unit/test/widget/heroes_test.dart
+16
-12
tabs_test.dart
packages/unit/test/widget/tabs_test.dart
+6
-4
No files found.
packages/flutter/lib/src/animation/animated_value.dart
View file @
ee802bfe
...
@@ -58,26 +58,27 @@ class AnimationTiming {
...
@@ -58,26 +58,27 @@ class AnimationTiming {
}
}
}
}
/// An animated variable with a concrete type
/// An animated variable with a concrete type
.
class
AnimatedValue
<
T
extends
dynamic
>
extends
AnimationTiming
implements
Animatable
{
class
AnimatedValue
<
T
extends
dynamic
>
extends
AnimationTiming
implements
Animatable
{
AnimatedValue
(
this
.
begin
,
{
this
.
end
,
Curve
curve
,
Curve
reverseCurve
})
AnimatedValue
(
this
.
begin
,
{
this
.
end
,
Curve
curve
,
Curve
reverseCurve
})
:
super
(
curve:
curve
,
reverseCurve:
reverseCurve
)
{
:
super
(
curve:
curve
,
reverseCurve:
reverseCurve
)
{
value
=
begin
;
value
=
begin
;
}
}
/// The current value of this variable
/// The current value of this variable
.
T
value
;
T
value
;
/// The value this variable has at the beginning of the animation
/// The value this variable has at the beginning of the animation
.
T
begin
;
T
begin
;
/// The value this variable has at the end of the animation
/// The value this variable has at the end of the animation
.
T
end
;
T
end
;
/// Returns the value this variable has at the given animation clock value
/// Returns the value this variable has at the given animation clock value
.
T
lerp
(
double
t
)
=>
begin
+
(
end
-
begin
)
*
t
;
T
lerp
(
double
t
)
=>
begin
+
(
end
-
begin
)
*
t
;
/// Updates the value of this variable according to the given animation clock value and direction
/// Updates the value of this variable according to the given animation clock
/// value and direction.
void
setProgress
(
double
t
,
AnimationDirection
direction
)
{
void
setProgress
(
double
t
,
AnimationDirection
direction
)
{
if
(
end
!=
null
)
{
if
(
end
!=
null
)
{
t
=
transform
(
t
,
direction
);
t
=
transform
(
t
,
direction
);
...
@@ -93,7 +94,7 @@ class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animat
...
@@ -93,7 +94,7 @@ class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animat
String
toString
()
=>
'AnimatedValue(begin=
$begin
, end=
$end
, value=
$value
)'
;
String
toString
()
=>
'AnimatedValue(begin=
$begin
, end=
$end
, value=
$value
)'
;
}
}
/// An animated variable containing a color
/// An animated variable containing a color
.
///
///
/// This class specializes the interpolation of AnimatedValue<Color> to be
/// This class specializes the interpolation of AnimatedValue<Color> to be
/// appropriate for colors.
/// appropriate for colors.
...
@@ -104,9 +105,9 @@ class AnimatedColorValue extends AnimatedValue<Color> {
...
@@ -104,9 +105,9 @@ class AnimatedColorValue extends AnimatedValue<Color> {
Color
lerp
(
double
t
)
=>
Color
.
lerp
(
begin
,
end
,
t
);
Color
lerp
(
double
t
)
=>
Color
.
lerp
(
begin
,
end
,
t
);
}
}
/// An animated variable containing a
rectangle
/// An animated variable containing a
size.
///
///
/// This class specializes the interpolation of AnimatedValue<
Rect
> to be
/// This class specializes the interpolation of AnimatedValue<
Size
> to be
/// appropriate for rectangles.
/// appropriate for rectangles.
class
AnimatedSizeValue
extends
AnimatedValue
<
Size
>
{
class
AnimatedSizeValue
extends
AnimatedValue
<
Size
>
{
AnimatedSizeValue
(
Size
begin
,
{
Size
end
,
Curve
curve
,
Curve
reverseCurve
})
AnimatedSizeValue
(
Size
begin
,
{
Size
end
,
Curve
curve
,
Curve
reverseCurve
})
...
@@ -115,7 +116,7 @@ class AnimatedSizeValue extends AnimatedValue<Size> {
...
@@ -115,7 +116,7 @@ class AnimatedSizeValue extends AnimatedValue<Size> {
Size
lerp
(
double
t
)
=>
Size
.
lerp
(
begin
,
end
,
t
);
Size
lerp
(
double
t
)
=>
Size
.
lerp
(
begin
,
end
,
t
);
}
}
/// An animated variable containing a rectangle
/// An animated variable containing a rectangle
.
///
///
/// This class specializes the interpolation of AnimatedValue<Rect> to be
/// This class specializes the interpolation of AnimatedValue<Rect> to be
/// appropriate for rectangles.
/// appropriate for rectangles.
...
@@ -125,3 +126,15 @@ class AnimatedRectValue extends AnimatedValue<Rect> {
...
@@ -125,3 +126,15 @@ class AnimatedRectValue extends AnimatedValue<Rect> {
Rect
lerp
(
double
t
)
=>
Rect
.
lerp
(
begin
,
end
,
t
);
Rect
lerp
(
double
t
)
=>
Rect
.
lerp
(
begin
,
end
,
t
);
}
}
/// An animated variable containing a int.
///
/// The inherited lerp() function doesn't work with ints because it multiplies
/// the begin and end types by a double, and int * double returns a double.
/// This class overrides the lerp() function to round off the result to an int.
class
AnimatedIntValue
extends
AnimatedValue
<
int
>
{
AnimatedIntValue
(
int
begin
,
{
int
end
,
Curve
curve
,
Curve
reverseCurve
})
:
super
(
begin
,
end:
end
,
curve:
curve
,
reverseCurve:
reverseCurve
);
int
lerp
(
double
t
)
=>
(
begin
+
(
end
-
begin
)
*
t
).
round
();
}
packages/flutter/lib/src/material/colors.dart
View file @
ee802bfe
...
@@ -14,11 +14,13 @@ class Colors {
...
@@ -14,11 +14,13 @@ class Colors {
static
const
black
=
const
Color
(
0xFF000000
);
static
const
black
=
const
Color
(
0xFF000000
);
static
const
black87
=
const
Color
(
0xDD000000
);
static
const
black87
=
const
Color
(
0xDD000000
);
static
const
black54
=
const
Color
(
0x8A000000
);
static
const
black54
=
const
Color
(
0x8A000000
);
static
const
black26
=
const
Color
(
0x42000000
);
// disabled radio buttons and text of disabled flat buttons in light theme (26% black)
static
const
black45
=
const
Color
(
0x73000000
);
// mask color
static
const
black26
=
const
Color
(
0x42000000
);
// disabled radio buttons and text of disabled flat buttons in light theme
static
const
black12
=
const
Color
(
0x1F000000
);
// background of disabled raised buttons in light theme
static
const
black12
=
const
Color
(
0x1F000000
);
// background of disabled raised buttons in light theme
static
const
white
=
const
Color
(
0xFFFFFFFF
);
static
const
white
=
const
Color
(
0xFFFFFFFF
);
static
const
white70
=
const
Color
(
0xB3FFFFFF
);
static
const
white70
=
const
Color
(
0xB3FFFFFF
);
static
const
white30
=
const
Color
(
0x4DFFFFFF
);
// disabled radio buttons and text of disabled flat buttons in dark theme
(30% white)
static
const
white30
=
const
Color
(
0x4DFFFFFF
);
// disabled radio buttons and text of disabled flat buttons in dark theme
static
const
white12
=
const
Color
(
0x1FFFFFFF
);
// background of disabled raised buttons in dark theme
static
const
white12
=
const
Color
(
0x1FFFFFFF
);
// background of disabled raised buttons in dark theme
static
const
white10
=
const
Color
(
0x1AFFFFFF
);
static
const
white10
=
const
Color
(
0x1AFFFFFF
);
...
...
packages/flutter/lib/src/material/drawer_item.dart
View file @
ee802bfe
...
@@ -10,35 +10,39 @@ import 'ink_well.dart';
...
@@ -10,35 +10,39 @@ import 'ink_well.dart';
import
'theme.dart'
;
import
'theme.dart'
;
class
DrawerItem
extends
StatelessComponent
{
class
DrawerItem
extends
StatelessComponent
{
const
DrawerItem
({
Key
key
,
this
.
icon
,
this
.
child
,
this
.
onPressed
,
this
.
selected
:
false
})
const
DrawerItem
({
:
super
(
key:
key
);
Key
key
,
this
.
icon
,
this
.
child
,
this
.
onPressed
,
this
.
selected
:
false
})
:
super
(
key:
key
);
final
String
icon
;
final
String
icon
;
final
Widget
child
;
final
Widget
child
;
final
VoidCallback
onPressed
;
final
VoidCallback
onPressed
;
final
bool
selected
;
final
bool
selected
;
ColorFilter
_getIconColorFilter
(
ThemeData
themeData
)
{
if
(
selected
)
{
if
(
themeData
.
brightness
==
ThemeBrightness
.
dark
)
return
new
ColorFilter
.
mode
(
themeData
.
accentColor
,
TransferMode
.
srcATop
);
return
new
ColorFilter
.
mode
(
themeData
.
primaryColor
,
TransferMode
.
srcATop
);
}
return
new
ColorFilter
.
mode
(
Colors
.
black45
,
TransferMode
.
dstIn
);
}
TextStyle
_getTextStyle
(
ThemeData
themeData
)
{
TextStyle
_getTextStyle
(
ThemeData
themeData
)
{
TextStyle
result
=
themeData
.
text
.
body2
;
TextStyle
result
=
themeData
.
text
.
body2
;
if
(
selected
)
if
(
selected
)
{
result
=
result
.
copyWith
(
color:
themeData
.
primaryColor
);
if
(
themeData
.
brightness
==
ThemeBrightness
.
dark
)
result
=
result
.
copyWith
(
color:
themeData
.
accentColor
);
else
result
=
result
.
copyWith
(
color:
themeData
.
primaryColor
);
}
return
result
;
return
result
;
}
}
Color
_getBackgroundColor
(
ThemeData
themeData
,
{
bool
highlight
})
{
if
(
highlight
)
return
themeData
.
highlightColor
;
if
(
selected
)
return
themeData
.
selectedColor
;
return
Colors
.
transparent
;
}
ColorFilter
_getColorFilter
(
ThemeData
themeData
)
{
if
(
selected
)
return
new
ColorFilter
.
mode
(
themeData
.
primaryColor
,
TransferMode
.
srcATop
);
return
new
ColorFilter
.
mode
(
const
Color
(
0x73000000
),
TransferMode
.
dstIn
);
}
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
ThemeData
themeData
=
Theme
.
of
(
context
);
ThemeData
themeData
=
Theme
.
of
(
context
);
...
@@ -49,7 +53,7 @@ class DrawerItem extends StatelessComponent {
...
@@ -49,7 +53,7 @@ class DrawerItem extends StatelessComponent {
padding:
const
EdgeDims
.
symmetric
(
horizontal:
16.0
),
padding:
const
EdgeDims
.
symmetric
(
horizontal:
16.0
),
child:
new
Icon
(
child:
new
Icon
(
icon:
icon
,
icon:
icon
,
colorFilter:
_getColorFilter
(
themeData
)
colorFilter:
_get
Icon
ColorFilter
(
themeData
)
)
)
)
)
);
);
...
@@ -70,8 +74,6 @@ class DrawerItem extends StatelessComponent {
...
@@ -70,8 +74,6 @@ class DrawerItem extends StatelessComponent {
height:
48.0
,
height:
48.0
,
child:
new
InkWell
(
child:
new
InkWell
(
onTap:
onPressed
,
onTap:
onPressed
,
defaultColor:
_getBackgroundColor
(
themeData
,
highlight:
false
),
highlightColor:
_getBackgroundColor
(
themeData
,
highlight:
true
),
child:
new
Row
(
flexChildren
)
child:
new
Row
(
flexChildren
)
)
)
);
);
...
...
packages/flutter/lib/src/material/flat_button.dart
View file @
ee802bfe
...
@@ -4,7 +4,6 @@
...
@@ -4,7 +4,6 @@
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'colors.dart'
;
import
'material_button.dart'
;
import
'material_button.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
...
@@ -12,11 +11,27 @@ class FlatButton extends MaterialButton {
...
@@ -12,11 +11,27 @@ class FlatButton extends MaterialButton {
FlatButton
({
FlatButton
({
Key
key
,
Key
key
,
Widget
child
,
Widget
child
,
ButtonColor
textTheme
,
Color
textColor
,
Color
disabledTextColor
,
this
.
color
,
this
.
colorBrightness
,
this
.
disabledColor
,
VoidCallback
onPressed
VoidCallback
onPressed
})
:
super
(
key:
key
,
})
:
super
(
key:
key
,
child:
child
,
child:
child
,
textTheme:
textTheme
,
textColor:
textColor
,
disabledTextColor:
disabledTextColor
,
onPressed:
onPressed
);
onPressed:
onPressed
);
// These default to null, meaning transparent.
final
Color
color
;
final
Color
disabledColor
;
/// Controls the default text color if the text color isn't explicit set.
final
ThemeBrightness
colorBrightness
;
_FlatButtonState
createState
()
=>
new
_FlatButtonState
();
_FlatButtonState
createState
()
=>
new
_FlatButtonState
();
}
}
...
@@ -24,19 +39,14 @@ class _FlatButtonState extends MaterialButtonState<FlatButton> {
...
@@ -24,19 +39,14 @@ class _FlatButtonState extends MaterialButtonState<FlatButton> {
int
get
elevation
=>
0
;
int
get
elevation
=>
0
;
Color
getColor
(
BuildContext
context
,
{
bool
highlight
})
{
Color
getColor
(
BuildContext
context
)
{
if
(!
config
.
enabled
||
!
highlight
)
if
(!
config
.
enabled
)
return
null
;
return
config
.
disabledColor
;
switch
(
Theme
.
of
(
context
).
brightness
)
{
return
config
.
color
;
case
ThemeBrightness
.
light
:
return
Colors
.
grey
[
400
];
case
ThemeBrightness
.
dark
:
return
Colors
.
grey
[
200
];
}
}
}
ThemeBrightness
getColorBrightness
(
BuildContext
context
)
{
ThemeBrightness
getColorBrightness
(
BuildContext
context
)
{
return
Theme
.
of
(
context
).
brightness
;
return
config
.
colorBrightness
??
Theme
.
of
(
context
).
brightness
;
}
}
}
}
packages/flutter/lib/src/material/floating_action_button.dart
View file @
ee802bfe
...
@@ -19,12 +19,16 @@ class FloatingActionButton extends StatefulComponent {
...
@@ -19,12 +19,16 @@ class FloatingActionButton extends StatefulComponent {
Key
key
,
Key
key
,
this
.
child
,
this
.
child
,
this
.
backgroundColor
,
this
.
backgroundColor
,
this
.
elevation
:
6
,
this
.
highlightElevation
:
12
,
this
.
onPressed
this
.
onPressed
})
:
super
(
key:
key
);
})
:
super
(
key:
key
);
final
Widget
child
;
final
Widget
child
;
final
Color
backgroundColor
;
final
Color
backgroundColor
;
final
VoidCallback
onPressed
;
final
VoidCallback
onPressed
;
final
int
elevation
;
final
int
highlightElevation
;
_FloatingActionButtonState
createState
()
=>
new
_FloatingActionButtonState
();
_FloatingActionButtonState
createState
()
=>
new
_FloatingActionButtonState
();
}
}
...
@@ -50,19 +54,17 @@ class _FloatingActionButtonState extends State<FloatingActionButton> {
...
@@ -50,19 +54,17 @@ class _FloatingActionButtonState extends State<FloatingActionButton> {
return
new
Material
(
return
new
Material
(
color:
materialColor
,
color:
materialColor
,
type:
MaterialType
.
circle
,
type:
MaterialType
.
circle
,
elevation:
_highlight
?
12
:
6
,
elevation:
_highlight
?
config
.
highlightElevation
:
config
.
elevation
,
child:
new
ClipOval
(
child:
new
Container
(
child:
new
Container
(
width:
_kSize
,
width:
_kSize
,
height:
_kSize
,
height:
_kSize
,
child:
new
InkWell
(
child:
new
InkWell
(
onTap:
config
.
onPressed
,
onTap:
config
.
onPressed
,
onHighlightChanged:
_handleHighlightChanged
,
onHighlightChanged:
_handleHighlightChanged
,
child:
new
Center
(
child:
new
Center
(
child:
new
IconTheme
(
child:
new
IconTheme
(
data:
new
IconThemeData
(
color:
iconThemeColor
),
data:
new
IconThemeData
(
color:
iconThemeColor
),
child:
config
.
child
child:
config
.
child
)
)
)
)
)
)
)
...
...
packages/flutter/lib/src/material/icon_button.dart
View file @
ee802bfe
...
@@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';
...
@@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';
import
'icon.dart'
;
import
'icon.dart'
;
import
'icon_theme_data.dart'
;
import
'icon_theme_data.dart'
;
import
'ink_well.dart'
;
class
IconButton
extends
StatelessComponent
{
class
IconButton
extends
StatelessComponent
{
const
IconButton
({
const
IconButton
({
...
@@ -22,11 +23,8 @@ class IconButton extends StatelessComponent {
...
@@ -22,11 +23,8 @@ class IconButton extends StatelessComponent {
final
VoidCallback
onPressed
;
final
VoidCallback
onPressed
;
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
// TODO(abarth): We should use a radial reaction here so you can hit the
return
new
InkResponse
(
// 8.0 pixel padding as well as the icon.
return
new
GestureDetector
(
onTap:
onPressed
,
onTap:
onPressed
,
behavior:
HitTestBehavior
.
opaque
,
child:
new
Padding
(
child:
new
Padding
(
padding:
const
EdgeDims
.
all
(
8.0
),
padding:
const
EdgeDims
.
all
(
8.0
),
child:
new
Icon
(
child:
new
Icon
(
...
...
packages/flutter/lib/src/material/ink_well.dart
View file @
ee802bfe
...
@@ -2,331 +2,193 @@
...
@@ -2,331 +2,193 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:math'
as
math
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
// This file has the following classes:
import
'material.dart'
;
// InkWell - the widget for material-design-style inkly-reacting material, showing splashes and a highlight
import
'theme.dart'
;
// _InkWellState - InkWell's State class
// _InkSplash - tracks a single splash
// _RenderInkSplashes - a RenderBox that renders multiple _InkSplash objects and handles gesture recognition
// _InkSplashes - the RenderObjectWidget for _RenderInkSplashes used by InkWell to handle the splashes
const
int
_kSplashInitialOpacity
=
0x30
;
// 0..255
const
double
_kSplashCanceledVelocity
=
0.7
;
// logical pixels per millisecond
const
double
_kSplashConfirmedVelocity
=
0.7
;
// logical pixels per millisecond
const
double
_kSplashInitialSize
=
0.0
;
// logical pixels
const
double
_kSplashUnconfirmedVelocity
=
0.2
;
// logical pixels per millisecond
const
Duration
_kInkWellHighlightFadeDuration
=
const
Duration
(
milliseconds:
100
);
class
Ink
Well
extends
StatefulComponent
{
class
Ink
Response
extends
StatefulComponent
{
Ink
Well
({
Ink
Response
({
Key
key
,
Key
key
,
this
.
child
,
this
.
child
,
this
.
onTap
,
this
.
onTap
,
this
.
onDoubleTap
,
this
.
onDoubleTap
,
this
.
onLongPress
,
this
.
onLongPress
,
this
.
onHighlightChanged
,
this
.
onHighlightChanged
this
.
defaultColor
,
this
.
highlightColor
})
:
super
(
key:
key
);
})
:
super
(
key:
key
);
final
Widget
child
;
final
Widget
child
;
final
GestureTapCallback
onTap
;
final
GestureTapCallback
onTap
;
final
GestureTapCallback
onDoubleTap
;
final
GestureTapCallback
onDoubleTap
;
final
GestureLongPressCallback
onLongPress
;
final
GestureLongPressCallback
onLongPress
;
final
_HighlightChangedCallback
onHighlightChanged
;
final
ValueChanged
<
bool
>
onHighlightChanged
;
final
Color
defaultColor
;
final
Color
highlightColor
;
_Ink
WellState
createState
()
=>
new
_InkWellState
();
_Ink
ResponseState
createState
()
=>
new
_InkResponseState
<
InkResponse
>
();
}
}
class
_InkWellState
extends
State
<
InkWell
>
{
class
_InkResponseState
<
T
extends
InkResponse
>
extends
State
<
T
>
{
bool
_highlight
=
false
;
Widget
build
(
BuildContext
context
)
{
return
new
AnimatedContainer
(
decoration:
new
BoxDecoration
(
backgroundColor:
_highlight
?
config
.
highlightColor
:
config
.
defaultColor
),
duration:
_kInkWellHighlightFadeDuration
,
child:
new
_InkSplashes
(
onTap:
config
.
onTap
,
onDoubleTap:
config
.
onDoubleTap
,
onLongPress:
config
.
onLongPress
,
onHighlightChanged:
(
bool
value
)
{
setState
(()
{
_highlight
=
value
;
});
if
(
config
.
onHighlightChanged
!=
null
)
config
.
onHighlightChanged
(
value
);
},
child:
config
.
child
)
);
}
}
bool
get
containedInWell
=>
false
;
double
_getSplashTargetSize
(
Size
bounds
,
Point
position
)
{
Set
<
InkSplash
>
_splashes
;
double
d1
=
(
position
-
bounds
.
topLeft
(
Point
.
origin
)).
distance
;
InkSplash
_currentSplash
;
double
d2
=
(
position
-
bounds
.
topRight
(
Point
.
origin
)).
distance
;
double
d3
=
(
position
-
bounds
.
bottomLeft
(
Point
.
origin
)).
distance
;
double
d4
=
(
position
-
bounds
.
bottomRight
(
Point
.
origin
)).
distance
;
return
math
.
max
(
math
.
max
(
d1
,
d2
),
math
.
max
(
d3
,
d4
)).
ceil
().
toDouble
();
}
class
_InkSplash
{
void
_handleTapDown
(
Point
position
)
{
_InkSplash
(
this
.
position
,
this
.
renderer
)
{
RenderBox
referenceBox
=
context
.
findRenderObject
();
_targetRadius
=
_getSplashTargetSize
(
renderer
.
size
,
position
);
assert
(
Material
.
of
(
context
)
!=
null
);
_radius
=
new
ValuePerformance
<
double
>(
InkSplash
splash
;
variable:
new
AnimatedValue
<
double
>(
splash
=
Material
.
of
(
context
).
splashAt
(
_kSplashInitialSize
,
referenceBox:
referenceBox
,
end:
_targetRadius
,
position:
referenceBox
.
globalToLocal
(
position
),
curve:
Curves
.
easeOut
containedInWell:
containedInWell
,
),
onRemoved:
()
{
duration:
new
Duration
(
milliseconds:
(
_targetRadius
/
_kSplashUnconfirmedVelocity
).
floor
())
if
(
_splashes
!=
null
)
{
)..
addListener
(
_handleRadiusChange
)
assert
(
_splashes
.
contains
(
splash
));
..
play
();
_splashes
.
remove
(
splash
);
if
(
_currentSplash
==
splash
)
_currentSplash
=
null
;
}
// else we're probably in deactivate()
}
);
_splashes
??=
new
Set
<
InkSplash
>();
_splashes
.
add
(
splash
);
_currentSplash
=
splash
;
}
}
final
Point
position
;
void
_handleTap
()
{
final
_RenderInkSplashes
renderer
;
_currentSplash
?.
confirm
();
_currentSplash
=
null
;
double
_targetRadius
;
if
(
config
.
onTap
!=
null
)
double
_pinnedRadius
;
config
.
onTap
();
ValuePerformance
<
double
>
_radius
;
void
_updateVelocity
(
double
velocity
)
{
int
duration
=
(
_targetRadius
/
velocity
).
floor
();
_radius
.
duration
=
new
Duration
(
milliseconds:
duration
);
_radius
.
play
();
}
}
void
confirm
()
{
void
_handleTapCancel
()
{
_
updateVelocity
(
_kSplashConfirmedVelocity
);
_
currentSplash
?.
cancel
(
);
_
pinnedRadius
=
null
;
_
currentSplash
=
null
;
}
}
void
cancel
()
{
void
_handleDoubleTap
()
{
_updateVelocity
(
_kSplashCanceledVelocity
);
_currentSplash
?.
confirm
();
_pinnedRadius
=
_radius
.
value
;
_currentSplash
=
null
;
if
(
config
.
onDoubleTap
!=
null
)
config
.
onDoubleTap
();
}
}
void
_handleRadiusChange
()
{
void
_handleLongPress
()
{
if
(
_radius
.
value
==
_targetRadius
)
_currentSplash
?.
confirm
();
renderer
.
_removeSplash
(
this
);
_currentSplash
=
null
;
renderer
.
markNeedsPaint
();
if
(
config
.
onLongPress
!=
null
)
config
.
onLongPress
();
}
void
deactivate
()
{
if
(
_splashes
!=
null
)
{
Set
<
InkSplash
>
splashes
=
_splashes
;
_splashes
=
null
;
for
(
InkSplash
splash
in
splashes
)
splash
.
dispose
();
_currentSplash
=
null
;
}
assert
(
_currentSplash
==
null
);
super
.
deactivate
();
}
}
void
paint
(
PaintingCanvas
canvas
)
{
Widget
build
(
BuildContext
context
)
{
int
opacity
=
(
_kSplashInitialOpacity
*
(
1.1
-
(
_radius
.
value
/
_targetRadius
))).
floor
();
final
bool
enabled
=
config
.
onTap
!=
null
||
config
.
onDoubleTap
!=
null
||
config
.
onLongPress
!=
null
;
Paint
paint
=
new
Paint
()..
color
=
new
Color
(
opacity
<<
24
);
return
new
GestureDetector
(
double
radius
=
_pinnedRadius
==
null
?
_radius
.
value
:
_pinnedRadius
;
onTapDown:
enabled
?
_handleTapDown
:
null
,
canvas
.
drawCircle
(
position
,
radius
,
paint
);
onTap:
enabled
?
_handleTap
:
null
,
onTapCancel:
enabled
?
_handleTapCancel
:
null
,
onDoubleTap:
config
.
onDoubleTap
!=
null
?
_handleDoubleTap
:
null
,
onLongPress:
config
.
onLongPress
!=
null
?
_handleLongPress
:
null
,
behavior:
HitTestBehavior
.
opaque
,
child:
config
.
child
);
}
}
}
typedef
_HighlightChangedCallback
(
bool
value
);
}
class
_RenderInkSplashes
extends
RenderProxyBox
{
/// An area of a Material that responds to touch.
_RenderInkSplashes
({
///
RenderBox
child
,
/// Must have an ancestor Material widget in which to cause ink reactions.
class
InkWell
extends
InkResponse
{
InkWell
({
Key
key
,
Widget
child
,
GestureTapCallback
onTap
,
GestureTapCallback
onTap
,
GestureTapCallback
onDoubleTap
,
GestureTapCallback
onDoubleTap
,
GestureLongPressCallback
onLongPress
,
GestureLongPressCallback
onLongPress
,
this
.
onHighlightChanged
this
.
onHighlightChanged
})
:
super
(
child
)
{
})
:
super
(
this
.
onTap
=
onTap
;
key:
key
,
this
.
onDoubleTap
=
onDoubleTap
;
child:
child
,
this
.
onLongPress
=
onLongPress
;
onTap:
onTap
,
}
onDoubleTap:
onDoubleTap
,
onLongPress:
onLongPress
GestureTapCallback
get
onTap
=>
_onTap
;
);
GestureTapCallback
_onTap
;
void
set
onTap
(
GestureTapCallback
value
)
{
_onTap
=
value
;
_syncTapRecognizer
();
}
GestureTapCallback
get
onDoubleTap
=>
_onDoubleTap
;
GestureTapCallback
_onDoubleTap
;
void
set
onDoubleTap
(
GestureTapCallback
value
)
{
_onDoubleTap
=
value
;
_syncDoubleTapRecognizer
();
}
GestureTapCallback
get
onLongPress
=>
_onLongPress
;
GestureTapCallback
_onLongPress
;
void
set
onLongPress
(
GestureTapCallback
value
)
{
_onLongPress
=
value
;
_syncLongPressRecognizer
();
}
_HighlightChangedCallback
onHighlightChanged
;
final
List
<
_InkSplash
>
_splashes
=
new
List
<
_InkSplash
>();
_InkSplash
_lastSplash
;
TapGestureRecognizer
_tap
;
DoubleTapGestureRecognizer
_doubleTap
;
LongPressGestureRecognizer
_longPress
;
void
_removeSplash
(
_InkSplash
splash
)
{
_splashes
.
remove
(
splash
);
if
(
_lastSplash
==
splash
)
_lastSplash
=
null
;
}
void
handleEvent
(
InputEvent
event
,
BoxHitTestEntry
entry
)
{
if
(
event
.
type
==
'pointerdown'
&&
(
onTap
!=
null
||
onDoubleTap
!=
null
||
onLongPress
!=
null
))
{
_tap
?.
addPointer
(
event
);
_doubleTap
?.
addPointer
(
event
);
_longPress
?.
addPointer
(
event
);
}
}
void
attach
()
{
super
.
attach
();
_syncTapRecognizer
();
_syncDoubleTapRecognizer
();
_syncLongPressRecognizer
();
}
void
detach
()
{
_disposeTapRecognizer
();
_disposeDoubleTapRecognizer
();
_disposeLongPressRecognizer
();
super
.
detach
();
}
void
_syncTapRecognizer
()
{
if
(
onTap
==
null
&&
onDoubleTap
==
null
&&
onLongPress
==
null
)
{
_disposeTapRecognizer
();
}
else
{
_tap
??=
new
TapGestureRecognizer
(
router:
FlutterBinding
.
instance
.
pointerRouter
)
..
onTapDown
=
_handleTapDown
..
onTap
=
_handleTap
..
onTapCancel
=
_handleTapCancel
;
}
}
void
_disposeTapRecognizer
()
{
final
ValueChanged
<
bool
>
onHighlightChanged
;
_tap
?.
dispose
();
_tap
=
null
;
}
void
_syncDoubleTapRecognizer
()
{
_InkWellState
createState
()
=>
new
_InkWellState
();
if
(
onDoubleTap
==
null
)
{
}
_disposeDoubleTapRecognizer
();
}
else
{
_doubleTap
??=
new
DoubleTapGestureRecognizer
(
router:
FlutterBinding
.
instance
.
pointerRouter
)
..
onDoubleTap
=
_handleDoubleTap
;
}
}
void
_disposeDoubleTapRecognizer
()
{
_doubleTap
?.
dispose
();
_doubleTap
=
null
;
}
void
_syncLongPressRecognizer
()
{
class
_InkWellState
extends
_InkResponseState
<
InkWell
>
{
if
(
onLongPress
==
null
)
{
_disposeLongPressRecognizer
();
bool
get
containedInWell
=>
true
;
InkHighlight
_lastHighlight
;
void
updateHighlight
(
bool
value
)
{
if
(
value
==
(
_lastHighlight
!=
null
&&
_lastHighlight
.
active
))
return
;
if
(
value
)
{
if
(
_lastHighlight
==
null
)
{
RenderBox
referenceBox
=
context
.
findRenderObject
();
assert
(
Material
.
of
(
context
)
!=
null
);
_lastHighlight
=
Material
.
of
(
context
).
highlightRectAt
(
referenceBox:
referenceBox
,
color:
Theme
.
of
(
context
).
highlightColor
,
onRemoved:
()
{
assert
(
_lastHighlight
!=
null
);
_lastHighlight
=
null
;
}
);
}
else
{
_lastHighlight
.
activate
();
}
}
else
{
}
else
{
_longPress
??=
new
LongPressGestureRecognizer
(
router:
FlutterBinding
.
instance
.
pointerRouter
)
_lastHighlight
.
deactivate
();
..
onLongPress
=
_handleLongPress
;
}
}
}
if
(
config
.
onHighlightChanged
!=
null
)
config
.
onHighlightChanged
(
value
!=
null
);
void
_disposeLongPressRecognizer
()
{
_longPress
?.
dispose
();
_longPress
=
null
;
}
}
void
_handleTapDown
(
Point
position
)
{
void
_handleTapDown
(
Point
position
)
{
_lastSplash
=
new
_InkSplash
(
globalToLocal
(
position
),
this
);
super
.
_handleTapDown
(
position
);
_splashes
.
add
(
_lastSplash
);
updateHighlight
(
true
);
if
(
onHighlightChanged
!=
null
)
onHighlightChanged
(
true
);
}
}
void
_handleTap
()
{
void
_handleTap
()
{
_lastSplash
?.
confirm
();
super
.
_handleTap
();
_lastSplash
=
null
;
updateHighlight
(
false
);
if
(
onHighlightChanged
!=
null
)
onHighlightChanged
(
false
);
if
(
onTap
!=
null
)
onTap
();
}
}
void
_handleTapCancel
()
{
void
_handleTapCancel
()
{
_lastSplash
?.
cancel
();
super
.
_handleTapCancel
();
_lastSplash
=
null
;
updateHighlight
(
false
);
if
(
onHighlightChanged
!=
null
)
onHighlightChanged
(
false
);
}
void
_handleDoubleTap
()
{
_lastSplash
?.
confirm
();
_lastSplash
=
null
;
if
(
onDoubleTap
!=
null
)
onDoubleTap
();
}
}
void
_handleLongPress
()
{
void
deactivate
()
{
_lastSplash
?.
confirm
();
_lastHighlight
?.
dispose
();
_lastSplash
=
null
;
_lastHighlight
=
null
;
if
(
onLongPress
!=
null
)
super
.
deactivate
();
onLongPress
();
}
}
bool
hitTestSelf
(
Point
position
)
=>
true
;
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
if
(
affectedWidgetType
==
Theme
&&
_lastHighlight
!=
null
)
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
_lastHighlight
.
color
=
Theme
.
of
(
context
).
highlightColor
;
if
(!
_splashes
.
isEmpty
)
{
final
PaintingCanvas
canvas
=
context
.
canvas
;
canvas
.
save
();
canvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
canvas
.
clipRect
(
Point
.
origin
&
size
);
for
(
_InkSplash
splash
in
_splashes
)
splash
.
paint
(
canvas
);
canvas
.
restore
();
}
super
.
paint
(
context
,
offset
);
}
}
}
class
_InkSplashes
extends
OneChildRenderObjectWidget
{
_InkSplashes
({
Key
key
,
Widget
child
,
this
.
onTap
,
this
.
onDoubleTap
,
this
.
onLongPress
,
this
.
onHighlightChanged
})
:
super
(
key:
key
,
child:
child
);
final
GestureTapCallback
onTap
;
final
GestureTapCallback
onDoubleTap
;
final
GestureLongPressCallback
onLongPress
;
final
_HighlightChangedCallback
onHighlightChanged
;
_RenderInkSplashes
createRenderObject
()
=>
new
_RenderInkSplashes
(
onTap:
onTap
,
onDoubleTap:
onDoubleTap
,
onLongPress:
onLongPress
,
onHighlightChanged:
onHighlightChanged
);
void
updateRenderObject
(
_RenderInkSplashes
renderObject
,
_InkSplashes
oldWidget
)
{
renderObject
.
onTap
=
onTap
;
renderObject
.
onDoubleTap
=
onDoubleTap
;
renderObject
.
onLongPress
=
onLongPress
;
renderObject
.
onHighlightChanged
=
onHighlightChanged
;
}
}
}
packages/flutter/lib/src/material/material.dart
View file @
ee802bfe
...
@@ -2,23 +2,76 @@
...
@@ -2,23 +2,76 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:math'
as
math
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'constants.dart'
;
import
'constants.dart'
;
import
'shadows.dart'
;
import
'shadows.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
enum
MaterialType
{
canvas
,
card
,
circle
,
button
}
enum
MaterialType
{
/// Infinite extent using default theme canvas color.
canvas
,
/// Rounded edges, card theme color.
card
,
const
Map
<
MaterialType
,
double
>
_kEdges
=
const
<
MaterialType
,
double
>{
/// A circle, no color by default (used for floating action buttons).
circle
,
/// Rounded edges, no color by default (used for MaterialButton buttons).
button
}
const
Map
<
MaterialType
,
double
>
kMaterialEdges
=
const
<
MaterialType
,
double
>{
MaterialType
.
canvas
:
null
,
MaterialType
.
canvas
:
null
,
MaterialType
.
card
:
2.0
,
MaterialType
.
card
:
2.0
,
MaterialType
.
circle
:
null
,
MaterialType
.
circle
:
null
,
MaterialType
.
button
:
2.0
,
MaterialType
.
button
:
2.0
,
};
};
class
Material
extends
StatelessComponent
{
abstract
class
InkSplash
{
void
confirm
();
void
cancel
();
void
dispose
();
}
abstract
class
InkHighlight
{
void
activate
();
void
deactivate
();
void
dispose
();
bool
get
active
;
Color
get
color
;
void
set
color
(
Color
value
);
}
abstract
class
MaterialInkController
{
/// The color of the material
Color
get
color
;
/// Begin a splash, centered at position relative to referenceBox.
/// If containedInWell is true, then the splash will be sized to fit
/// the referenceBox, then clipped to it when drawn.
/// When the splash is removed, onRemoved will be invoked.
InkSplash
splashAt
({
RenderBox
referenceBox
,
Point
position
,
bool
containedInWell
,
VoidCallback
onRemoved
});
/// Begin a highlight, coincident with the referenceBox.
InkHighlight
highlightRectAt
({
RenderBox
referenceBox
,
Color
color
,
VoidCallback
onRemoved
});
/// Add an arbitrary InkFeature to this InkController.
void
addInkFeature
(
InkFeature
feature
);
}
/// Describes a sheet of Material. If the layout changes (e.g. because there's a
/// list on the paper, and it's been scrolled), a LayoutChangedNotification must
/// be dispatched at the relevant subtree. (This in particular means that
/// Transitions should not be placed inside Material.)
class
Material
extends
StatefulComponent
{
Material
({
Material
({
Key
key
,
Key
key
,
this
.
child
,
this
.
child
,
...
@@ -36,10 +89,21 @@ class Material extends StatelessComponent {
...
@@ -36,10 +89,21 @@ class Material extends StatelessComponent {
final
Color
color
;
final
Color
color
;
final
TextStyle
textStyle
;
final
TextStyle
textStyle
;
static
MaterialInkController
of
(
BuildContext
context
)
{
final
RenderInkFeatures
result
=
context
.
ancestorRenderObjectOfType
(
RenderInkFeatures
);
return
result
;
}
_MaterialState
createState
()
=>
new
_MaterialState
();
}
class
_MaterialState
extends
State
<
Material
>
{
final
GlobalKey
_inkFeatureRenderer
=
new
GlobalKey
(
debugLabel:
'ink renderer'
);
Color
_getBackgroundColor
(
BuildContext
context
)
{
Color
_getBackgroundColor
(
BuildContext
context
)
{
if
(
color
!=
null
)
if
(
co
nfig
.
co
lor
!=
null
)
return
color
;
return
co
nfig
.
co
lor
;
switch
(
type
)
{
switch
(
config
.
type
)
{
case
MaterialType
.
canvas
:
case
MaterialType
.
canvas
:
return
Theme
.
of
(
context
).
canvasColor
;
return
Theme
.
of
(
context
).
canvasColor
;
case
MaterialType
.
card
:
case
MaterialType
.
card
:
...
@@ -50,33 +114,333 @@ class Material extends StatelessComponent {
...
@@ -50,33 +114,333 @@ class Material extends StatelessComponent {
}
}
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
Widget
contents
=
child
;
Color
backgroundColor
=
_getBackgroundColor
(
context
);
if
(
child
!=
null
)
{
Widget
contents
=
config
.
child
;
if
(
contents
!=
null
)
{
contents
=
new
DefaultTextStyle
(
contents
=
new
DefaultTextStyle
(
style:
textStyle
??
Theme
.
of
(
context
).
text
.
body1
,
style:
config
.
textStyle
??
Theme
.
of
(
context
).
text
.
body1
,
child:
contents
child:
contents
);
);
if
(
_kEdges
[
type
]
!=
null
)
{
contents
=
new
ClipRRect
(
xRadius:
_kEdges
[
type
],
yRadius:
_kEdges
[
type
],
child:
contents
);
}
}
}
return
new
DefaultTextStyle
(
contents
=
new
NotificationListener
<
LayoutChangedNotification
>(
style:
Theme
.
of
(
context
).
text
.
body1
,
onNotification:
(
LayoutChangedNotification
notification
)
{
child:
new
AnimatedContainer
(
_inkFeatureRenderer
.
currentContext
.
findRenderObject
().
markNeedsPaint
();
curve:
Curves
.
ease
,
},
duration:
kThemeChangeDuration
,
child:
new
InkFeatures
(
decoration:
new
BoxDecoration
(
key:
_inkFeatureRenderer
,
backgroundColor:
_getBackgroundColor
(
context
),
color:
backgroundColor
,
borderRadius:
_kEdges
[
type
],
boxShadow:
elevation
==
0
?
null
:
elevationToShadow
[
elevation
],
shape:
type
==
MaterialType
.
circle
?
Shape
.
circle
:
Shape
.
rectangle
),
child:
contents
child:
contents
)
)
);
);
if
(
config
.
type
==
MaterialType
.
circle
)
{
contents
=
new
ClipOval
(
child:
contents
);
}
else
if
(
kMaterialEdges
[
config
.
type
]
!=
null
)
{
contents
=
new
ClipRRect
(
xRadius:
kMaterialEdges
[
config
.
type
],
yRadius:
kMaterialEdges
[
config
.
type
],
child:
contents
);
}
contents
=
new
AnimatedContainer
(
curve:
Curves
.
ease
,
duration:
kThemeChangeDuration
,
decoration:
new
BoxDecoration
(
backgroundColor:
backgroundColor
,
borderRadius:
kMaterialEdges
[
config
.
type
],
boxShadow:
config
.
elevation
==
0
?
null
:
elevationToShadow
[
config
.
elevation
],
shape:
config
.
type
==
MaterialType
.
circle
?
Shape
.
circle
:
Shape
.
rectangle
),
child:
contents
);
return
contents
;
}
}
const
Duration
_kHighlightFadeDuration
=
const
Duration
(
milliseconds:
100
);
const
double
_kDefaultSplashRadius
=
35.0
;
// logical pixels
const
int
_kSplashInitialAlpha
=
0x30
;
// 0..255
const
double
_kSplashCanceledVelocity
=
0.7
;
// logical pixels per millisecond
const
double
_kSplashConfirmedVelocity
=
0.7
;
// logical pixels per millisecond
const
double
_kSplashInitialSize
=
0.0
;
// logical pixels
const
double
_kSplashUnconfirmedVelocity
=
0.2
;
// logical pixels per millisecond
class
RenderInkFeatures
extends
RenderProxyBox
implements
MaterialInkController
{
RenderInkFeatures
({
RenderBox
child
,
this
.
color
})
:
super
(
child
);
// This is here to satisfy the MaterialInkController contract.
// The actual painting of this color is done by a Container in the
// MaterialState build method.
Color
color
;
final
List
<
InkFeature
>
_inkFeatures
=
<
InkFeature
>[];
InkSplash
splashAt
({
RenderBox
referenceBox
,
Point
position
,
bool
containedInWell
,
VoidCallback
onRemoved
})
{
double
radius
;
if
(
containedInWell
)
{
radius
=
_getSplashTargetSize
(
referenceBox
.
size
,
position
);
}
else
{
radius
=
_kDefaultSplashRadius
;
}
_InkSplash
splash
=
new
_InkSplash
(
renderer:
this
,
referenceBox:
referenceBox
,
position:
position
,
targetRadius:
radius
,
clipToReferenceBox:
containedInWell
,
onRemoved:
onRemoved
);
addInkFeature
(
splash
);
return
splash
;
}
double
_getSplashTargetSize
(
Size
bounds
,
Point
position
)
{
double
d1
=
(
position
-
bounds
.
topLeft
(
Point
.
origin
)).
distance
;
double
d2
=
(
position
-
bounds
.
topRight
(
Point
.
origin
)).
distance
;
double
d3
=
(
position
-
bounds
.
bottomLeft
(
Point
.
origin
)).
distance
;
double
d4
=
(
position
-
bounds
.
bottomRight
(
Point
.
origin
)).
distance
;
return
math
.
max
(
math
.
max
(
d1
,
d2
),
math
.
max
(
d3
,
d4
)).
ceilToDouble
();
}
InkHighlight
highlightRectAt
({
RenderBox
referenceBox
,
Color
color
,
VoidCallback
onRemoved
})
{
_InkHighlight
highlight
=
new
_InkHighlight
(
renderer:
this
,
referenceBox:
referenceBox
,
color:
color
,
onRemoved:
onRemoved
);
addInkFeature
(
highlight
);
return
highlight
;
}
void
addInkFeature
(
InkFeature
feature
)
{
assert
(!
feature
.
_debugDisposed
);
assert
(
feature
.
renderer
==
this
);
assert
(!
_inkFeatures
.
contains
(
feature
));
_inkFeatures
.
add
(
feature
);
markNeedsPaint
();
}
void
_removeFeature
(
InkFeature
feature
)
{
_inkFeatures
.
remove
(
feature
);
markNeedsPaint
();
}
bool
hitTestSelf
(
Point
position
)
=>
true
;
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
_inkFeatures
.
isNotEmpty
)
{
final
Canvas
canvas
=
context
.
canvas
;
canvas
.
save
();
canvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
canvas
.
clipRect
(
Point
.
origin
&
size
);
for
(
InkFeature
inkFeature
in
_inkFeatures
)
inkFeature
.
_paint
(
canvas
);
canvas
.
restore
();
}
super
.
paint
(
context
,
offset
);
}
}
class
InkFeatures
extends
OneChildRenderObjectWidget
{
InkFeatures
({
Key
key
,
this
.
color
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
final
Color
color
;
RenderInkFeatures
createRenderObject
()
=>
new
RenderInkFeatures
(
color:
color
);
void
updateRenderObject
(
RenderInkFeatures
renderObject
,
InkFeatures
oldWidget
)
{
renderObject
.
color
=
color
;
}
}
abstract
class
InkFeature
{
InkFeature
({
this
.
renderer
,
this
.
referenceBox
,
this
.
onRemoved
});
final
RenderInkFeatures
renderer
;
final
RenderBox
referenceBox
;
final
VoidCallback
onRemoved
;
bool
_debugDisposed
=
false
;
void
dispose
()
{
assert
(!
_debugDisposed
);
assert
(()
{
_debugDisposed
=
true
;
return
true
;
});
renderer
.
_removeFeature
(
this
);
if
(
onRemoved
!=
null
)
onRemoved
();
}
void
_paint
(
Canvas
canvas
)
{
assert
(
referenceBox
.
attached
);
assert
(!
_debugDisposed
);
// find the chain of renderers from us to the feature's referenceBox
List
<
RenderBox
>
descendants
=
<
RenderBox
>[];
RenderBox
node
=
referenceBox
;
while
(
node
!=
renderer
)
{
descendants
.
add
(
node
);
node
=
node
.
parent
;
assert
(
node
!=
null
);
}
// determine the transform that gets our coordinate system to be like theirs
Matrix4
transform
=
new
Matrix4
.
identity
();
for
(
RenderBox
descendant
in
descendants
.
reversed
)
descendant
.
applyPaintTransform
(
transform
);
paintFeature
(
canvas
,
transform
);
}
void
paintFeature
(
Canvas
canvas
,
Matrix4
transform
);
String
toString
()
=>
"
$runtimeType
@
$hashCode
"
;
}
class
_InkSplash
extends
InkFeature
implements
InkSplash
{
_InkSplash
({
RenderInkFeatures
renderer
,
RenderBox
referenceBox
,
this
.
position
,
this
.
targetRadius
,
this
.
clipToReferenceBox
,
VoidCallback
onRemoved
})
:
super
(
renderer:
renderer
,
referenceBox:
referenceBox
,
onRemoved:
onRemoved
)
{
_radius
=
new
ValuePerformance
<
double
>(
variable:
new
AnimatedValue
<
double
>(
_kSplashInitialSize
,
end:
targetRadius
,
curve:
Curves
.
easeOut
),
duration:
new
Duration
(
milliseconds:
(
targetRadius
/
_kSplashUnconfirmedVelocity
).
floor
())
)..
addListener
(
_handleRadiusChange
)
..
play
();
}
}
final
Point
position
;
final
double
targetRadius
;
final
bool
clipToReferenceBox
;
double
_pinnedRadius
;
ValuePerformance
<
double
>
_radius
;
void
confirm
()
{
_updateVelocity
(
_kSplashConfirmedVelocity
);
}
void
cancel
()
{
_updateVelocity
(
_kSplashCanceledVelocity
);
_pinnedRadius
=
_radius
.
value
;
}
void
_updateVelocity
(
double
velocity
)
{
int
duration
=
(
targetRadius
/
velocity
).
floor
();
_radius
.
duration
=
new
Duration
(
milliseconds:
duration
);
_radius
.
play
();
}
void
_handleRadiusChange
()
{
if
(
_radius
.
value
==
targetRadius
)
dispose
();
else
renderer
.
markNeedsPaint
();
}
void
dispose
()
{
_radius
.
stop
();
super
.
dispose
();
}
void
paintFeature
(
Canvas
canvas
,
Matrix4
transform
)
{
int
alpha
=
(
_kSplashInitialAlpha
*
(
1.1
-
(
_radius
.
value
/
targetRadius
))).
floor
();
Paint
paint
=
new
Paint
()..
color
=
new
Color
(
alpha
<<
24
);
// TODO(ianh): in dark theme, this isn't very visible
double
radius
=
_pinnedRadius
==
null
?
_radius
.
value
:
_pinnedRadius
;
Offset
originOffset
=
MatrixUtils
.
getAsTranslation
(
transform
);
if
(
originOffset
==
null
)
{
canvas
.
save
();
canvas
.
concat
(
transform
.
storage
);
if
(
clipToReferenceBox
)
canvas
.
clipRect
(
Point
.
origin
&
referenceBox
.
size
);
canvas
.
drawCircle
(
position
,
radius
,
paint
);
canvas
.
restore
();
}
else
{
if
(
clipToReferenceBox
)
{
canvas
.
save
();
canvas
.
clipRect
(
originOffset
.
toPoint
()
&
referenceBox
.
size
);
}
canvas
.
drawCircle
(
position
+
originOffset
,
radius
,
paint
);
if
(
clipToReferenceBox
)
canvas
.
restore
();
}
}
}
class
_InkHighlight
extends
InkFeature
implements
InkHighlight
{
_InkHighlight
({
RenderInkFeatures
renderer
,
RenderBox
referenceBox
,
Color
color
,
VoidCallback
onRemoved
})
:
_color
=
color
,
super
(
renderer:
renderer
,
referenceBox:
referenceBox
,
onRemoved:
onRemoved
)
{
_alpha
=
new
ValuePerformance
<
int
>(
variable:
new
AnimatedIntValue
(
0
,
end:
color
.
alpha
,
curve:
Curves
.
linear
),
duration:
_kHighlightFadeDuration
)..
addListener
(
_handleAlphaChange
)
..
play
();
}
Color
get
color
=>
_color
;
Color
_color
;
void
set
color
(
Color
value
)
{
if
(
value
==
_color
)
return
;
_color
=
value
;
renderer
.
markNeedsPaint
();
}
bool
get
active
=>
_active
;
bool
_active
=
true
;
ValuePerformance
<
int
>
_alpha
;
void
activate
()
{
_active
=
true
;
_alpha
.
forward
();
}
void
deactivate
()
{
_active
=
false
;
_alpha
.
reverse
();
}
void
_handleAlphaChange
()
{
if
(
_alpha
.
value
==
0.0
&&
!
_active
)
dispose
();
else
renderer
.
markNeedsPaint
();
}
void
dispose
()
{
_alpha
.
stop
();
super
.
dispose
();
}
void
paintFeature
(
Canvas
canvas
,
Matrix4
transform
)
{
Paint
paint
=
new
Paint
()..
color
=
color
.
withAlpha
(
_alpha
.
value
);
Offset
originOffset
=
MatrixUtils
.
getAsTranslation
(
transform
);
if
(
originOffset
==
null
)
{
canvas
.
save
();
canvas
.
concat
(
transform
.
storage
);
canvas
.
drawRect
(
Point
.
origin
&
referenceBox
.
size
,
paint
);
canvas
.
restore
();
}
else
{
canvas
.
drawRect
(
originOffset
.
toPoint
()
&
referenceBox
.
size
,
paint
);
}
}
}
}
packages/flutter/lib/src/material/material_button.dart
View file @
ee802bfe
...
@@ -36,12 +36,16 @@ abstract class MaterialButton extends StatefulComponent {
...
@@ -36,12 +36,16 @@ abstract class MaterialButton extends StatefulComponent {
MaterialButton
({
MaterialButton
({
Key
key
,
Key
key
,
this
.
child
,
this
.
child
,
this
.
textTheme
,
this
.
textColor
,
this
.
textColor
,
this
.
disabledTextColor
,
this
.
onPressed
this
.
onPressed
})
:
super
(
key:
key
);
})
:
super
(
key:
key
);
final
Widget
child
;
final
Widget
child
;
final
ButtonColor
textColor
;
final
ButtonColor
textTheme
;
final
Color
textColor
;
final
Color
disabledTextColor
;
final
VoidCallback
onPressed
;
final
VoidCallback
onPressed
;
bool
get
enabled
=>
onPressed
!=
null
;
bool
get
enabled
=>
onPressed
!=
null
;
...
@@ -57,12 +61,14 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
...
@@ -57,12 +61,14 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
bool
highlight
=
false
;
bool
highlight
=
false
;
int
get
elevation
;
int
get
elevation
;
Color
getColor
(
BuildContext
context
,
{
bool
highlight
}
);
Color
getColor
(
BuildContext
context
);
ThemeBrightness
getColorBrightness
(
BuildContext
context
);
ThemeBrightness
getColorBrightness
(
BuildContext
context
);
Color
getTextColor
(
BuildContext
context
)
{
Color
getTextColor
(
BuildContext
context
)
{
if
(
config
.
enabled
)
{
if
(
config
.
enabled
)
{
switch
(
config
.
textColor
??
ButtonTheme
.
of
(
context
))
{
if
(
config
.
textColor
!=
null
)
return
config
.
textColor
;
switch
(
config
.
textTheme
??
ButtonTheme
.
of
(
context
))
{
case
ButtonColor
.
accent
:
case
ButtonColor
.
accent
:
return
Theme
.
of
(
context
).
accentColor
;
return
Theme
.
of
(
context
).
accentColor
;
case
ButtonColor
.
normal
:
case
ButtonColor
.
normal
:
...
@@ -74,6 +80,8 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
...
@@ -74,6 +80,8 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
}
}
}
}
}
}
if
(
config
.
disabledTextColor
!=
null
)
return
config
.
disabledTextColor
;
switch
(
getColorBrightness
(
context
))
{
switch
(
getColorBrightness
(
context
))
{
case
ThemeBrightness
.
light
:
case
ThemeBrightness
.
light
:
return
Colors
.
black26
;
return
Colors
.
black26
;
...
@@ -84,34 +92,45 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
...
@@ -84,34 +92,45 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
void
_handleHighlightChanged
(
bool
value
)
{
void
_handleHighlightChanged
(
bool
value
)
{
setState
(()
{
setState
(()
{
// mostly just used by the RaisedButton subclass to change the elevation
highlight
=
value
;
highlight
=
value
;
});
});
}
}
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
Widget
contents
=
new
Container
(
Widget
contents
=
new
InkWell
(
padding:
new
EdgeDims
.
symmetric
(
horizontal:
8.0
),
onTap:
config
.
onPressed
,
child:
new
Center
(
onHighlightChanged:
_handleHighlightChanged
,
widthFactor:
1.0
,
child:
new
Container
(
child:
config
.
child
padding:
new
EdgeDims
.
symmetric
(
horizontal:
8.0
),
child:
new
Center
(
widthFactor:
1.0
,
child:
config
.
child
)
)
)
);
);
TextStyle
style
=
Theme
.
of
(
context
).
text
.
button
.
copyWith
(
color:
getTextColor
(
context
));
int
elevation
=
this
.
elevation
;
Color
color
=
getColor
(
context
);
if
(
elevation
>
0
||
color
!=
null
)
{
contents
=
new
Material
(
type:
MaterialType
.
button
,
color:
getColor
(
context
),
elevation:
elevation
,
textStyle:
style
,
child:
contents
);
}
else
{
contents
=
new
DefaultTextStyle
(
style:
style
,
child:
contents
);
}
return
new
Container
(
return
new
Container
(
height:
36.0
,
height:
36.0
,
constraints:
new
BoxConstraints
(
minWidth:
88.0
),
constraints:
new
BoxConstraints
(
minWidth:
88.0
),
margin:
new
EdgeDims
.
all
(
8.0
),
margin:
new
EdgeDims
.
all
(
8.0
),
child:
new
Material
(
child:
contents
type:
MaterialType
.
button
,
elevation:
elevation
,
textStyle:
Theme
.
of
(
context
).
text
.
button
.
copyWith
(
color:
getTextColor
(
context
)),
child:
new
InkWell
(
onTap:
config
.
enabled
?
config
.
onPressed
:
null
,
defaultColor:
getColor
(
context
,
highlight:
false
),
highlightColor:
getColor
(
context
,
highlight:
true
),
onHighlightChanged:
_handleHighlightChanged
,
child:
contents
)
)
);
);
}
}
}
}
packages/flutter/lib/src/material/raised_button.dart
View file @
ee802bfe
...
@@ -12,36 +12,56 @@ class RaisedButton extends MaterialButton {
...
@@ -12,36 +12,56 @@ class RaisedButton extends MaterialButton {
RaisedButton
({
RaisedButton
({
Key
key
,
Key
key
,
Widget
child
,
Widget
child
,
this
.
color
,
this
.
colorBrightness
,
this
.
disabledColor
,
this
.
elevation
:
2
,
this
.
highlightElevation
:
8
,
this
.
disabledElevation
:
0
,
VoidCallback
onPressed
VoidCallback
onPressed
})
:
super
(
key:
key
,
})
:
super
(
key:
key
,
child:
child
,
child:
child
,
onPressed:
onPressed
);
onPressed:
onPressed
);
final
Color
color
;
final
Color
disabledColor
;
/// Controls the default text color if the text color isn't explicit set.
final
ThemeBrightness
colorBrightness
;
final
int
elevation
;
final
int
highlightElevation
;
final
int
disabledElevation
;
_RaisedButtonState
createState
()
=>
new
_RaisedButtonState
();
_RaisedButtonState
createState
()
=>
new
_RaisedButtonState
();
}
}
class
_RaisedButtonState
extends
MaterialButtonState
<
RaisedButton
>
{
class
_RaisedButtonState
extends
MaterialButtonState
<
RaisedButton
>
{
int
get
elevation
=>
config
.
enabled
?
(
highlight
?
8
:
2
)
:
0
;
int
get
elevation
{
if
(
config
.
enabled
)
{
if
(
highlight
)
return
config
.
highlightElevation
;
return
config
.
elevation
;
}
else
{
return
config
.
disabledElevation
;
}
}
Color
getColor
(
BuildContext
context
,
{
bool
highlight
}
)
{
Color
getColor
(
BuildContext
context
)
{
if
(
config
.
enabled
)
{
if
(
config
.
enabled
)
{
if
(
config
.
color
!=
null
)
return
config
.
color
;
switch
(
Theme
.
of
(
context
).
brightness
)
{
switch
(
Theme
.
of
(
context
).
brightness
)
{
case
ThemeBrightness
.
light
:
case
ThemeBrightness
.
light
:
if
(
highlight
)
return
Colors
.
grey
[
300
];
return
Colors
.
grey
[
350
];
else
return
Colors
.
grey
[
300
];
break
;
case
ThemeBrightness
.
dark
:
case
ThemeBrightness
.
dark
:
Map
<
int
,
Color
>
swatch
=
Theme
.
of
(
context
).
primarySwatch
??
Colors
.
blue
;
Map
<
int
,
Color
>
swatch
=
Theme
.
of
(
context
).
primarySwatch
??
Colors
.
blue
;
if
(
highlight
)
return
swatch
[
600
];
return
swatch
[
700
];
else
return
swatch
[
600
];
break
;
}
}
}
else
{
}
else
{
if
(
config
.
disabledColor
!=
null
)
return
config
.
disabledColor
;
switch
(
Theme
.
of
(
context
).
brightness
)
{
switch
(
Theme
.
of
(
context
).
brightness
)
{
case
ThemeBrightness
.
light
:
case
ThemeBrightness
.
light
:
return
Colors
.
black12
;
return
Colors
.
black12
;
...
@@ -52,7 +72,7 @@ class _RaisedButtonState extends MaterialButtonState<RaisedButton> {
...
@@ -52,7 +72,7 @@ class _RaisedButtonState extends MaterialButtonState<RaisedButton> {
}
}
ThemeBrightness
getColorBrightness
(
BuildContext
context
)
{
ThemeBrightness
getColorBrightness
(
BuildContext
context
)
{
return
Theme
.
of
(
context
).
brightness
;
return
config
.
colorBrightness
??
Theme
.
of
(
context
).
brightness
;
}
}
}
}
packages/flutter/lib/src/material/scaffold.dart
View file @
ee802bfe
...
@@ -115,7 +115,10 @@ class ScaffoldState extends State<Scaffold> {
...
@@ -115,7 +115,10 @@ class ScaffoldState extends State<Scaffold> {
}
}
ScaffoldFeatureController
<
SnackBar
>
controller
;
ScaffoldFeatureController
<
SnackBar
>
controller
;
controller
=
new
ScaffoldFeatureController
<
SnackBar
>.
_
(
controller
=
new
ScaffoldFeatureController
<
SnackBar
>.
_
(
snackbar
.
withPerformance
(
_snackBarPerformance
),
// We provide a fallback key so that if back-to-back snackbars happen to
// match in structure, material ink splashes and highlights don't survive
// from one to the next.
snackbar
.
withPerformance
(
_snackBarPerformance
,
fallbackKey:
new
UniqueKey
()),
new
Completer
(),
new
Completer
(),
()
{
()
{
assert
(
_snackBars
.
first
==
controller
);
assert
(
_snackBars
.
first
==
controller
);
...
...
packages/flutter/lib/src/material/snack_bar.dart
View file @
ee802bfe
...
@@ -5,14 +5,18 @@
...
@@ -5,14 +5,18 @@
import
'package:flutter/animation.dart'
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'flat_button.dart'
;
import
'material.dart'
;
import
'material.dart'
;
import
'material_button.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
import
'theme_data.dart'
;
import
'typography.dart'
;
import
'typography.dart'
;
// https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs
// https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs
const
double
_kSideMargins
=
24.0
;
const
double
_kSideMargins
=
24.0
;
const
double
_kSingleLineVerticalPadding
=
14.0
;
const
double
_kSingleLineVerticalPadding
=
14.0
;
const
double
_kMultiLineVerticalPadding
=
24.0
;
const
double
_kMultiLineVerticalTopPadding
=
24.0
;
const
double
_kMultiLineVerticalSpaceBetweenTextAndButtons
=
10.0
;
const
Color
_kSnackBackground
=
const
Color
(
0xFF323232
);
const
Color
_kSnackBackground
=
const
Color
(
0xFF323232
);
// TODO(ianh): We should check if the given text and actions are going to fit on
// TODO(ianh): We should check if the given text and actions are going to fit on
...
@@ -35,11 +39,11 @@ class SnackBarAction extends StatelessComponent {
...
@@ -35,11 +39,11 @@ class SnackBarAction extends StatelessComponent {
final
VoidCallback
onPressed
;
final
VoidCallback
onPressed
;
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
new
GestureDetecto
r
(
return
new
Containe
r
(
onTap:
onPressed
,
margin:
const
EdgeDims
.
only
(
left:
_kSideMargins
)
,
child:
new
Container
(
child:
new
FlatButton
(
margin:
const
EdgeDims
.
only
(
left:
_kSideMargins
)
,
onPressed:
onPressed
,
padding:
const
EdgeDims
.
symmetric
(
vertical:
_kSingleLineVerticalPadding
)
,
textTheme:
ButtonColor
.
accent
,
child:
new
Text
(
label
)
child:
new
Text
(
label
)
)
)
);
);
...
@@ -77,6 +81,7 @@ class SnackBar extends StatelessComponent {
...
@@ -77,6 +81,7 @@ class SnackBar extends StatelessComponent {
];
];
if
(
actions
!=
null
)
if
(
actions
!=
null
)
children
.
addAll
(
actions
);
children
.
addAll
(
actions
);
ThemeData
theme
=
Theme
.
of
(
context
);
return
new
ClipRect
(
return
new
ClipRect
(
child:
new
AlignTransition
(
child:
new
AlignTransition
(
performance:
performance
,
performance:
performance
,
...
@@ -87,12 +92,20 @@ class SnackBar extends StatelessComponent {
...
@@ -87,12 +92,20 @@ class SnackBar extends StatelessComponent {
color:
_kSnackBackground
,
color:
_kSnackBackground
,
child:
new
Container
(
child:
new
Container
(
margin:
const
EdgeDims
.
symmetric
(
horizontal:
_kSideMargins
),
margin:
const
EdgeDims
.
symmetric
(
horizontal:
_kSideMargins
),
child:
new
DefaultTextStyle
(
child:
new
Theme
(
style:
new
TextStyle
(
color:
Theme
.
of
(
context
).
accentColor
),
data:
new
ThemeData
(
brightness:
ThemeBrightness
.
dark
,
accentColor:
theme
.
accentColor
,
accentColorBrightness:
theme
.
accentColorBrightness
,
text:
Typography
.
white
),
child:
new
FadeTransition
(
child:
new
FadeTransition
(
performance:
performance
,
performance:
performance
,
opacity:
new
AnimatedValue
<
double
>(
0.0
,
end:
1.0
,
curve:
_snackBarFadeCurve
),
opacity:
new
AnimatedValue
<
double
>(
0.0
,
end:
1.0
,
curve:
_snackBarFadeCurve
),
child:
new
Row
(
children
)
child:
new
Row
(
children
,
alignItems:
FlexAlignItems
.
center
)
)
)
)
)
)
)
...
@@ -110,9 +123,9 @@ class SnackBar extends StatelessComponent {
...
@@ -110,9 +123,9 @@ class SnackBar extends StatelessComponent {
);
);
}
}
SnackBar
withPerformance
(
Performance
newPerformance
)
{
SnackBar
withPerformance
(
Performance
newPerformance
,
{
Key
fallbackKey
}
)
{
return
new
SnackBar
(
return
new
SnackBar
(
key:
key
,
key:
key
??
fallbackKey
,
content:
content
,
content:
content
,
actions:
actions
,
actions:
actions
,
duration:
duration
,
duration:
duration
,
...
...
packages/flutter/lib/src/material/tabs.dart
View file @
ee802bfe
...
@@ -10,11 +10,11 @@ import 'package:flutter/rendering.dart';
...
@@ -10,11 +10,11 @@ import 'package:flutter/rendering.dart';
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'colors.dart'
;
import
'colors.dart'
;
import
'constants.dart'
;
import
'icon.dart'
;
import
'icon.dart'
;
import
'icon_theme.dart'
;
import
'icon_theme.dart'
;
import
'icon_theme_data.dart'
;
import
'icon_theme_data.dart'
;
import
'ink_well.dart'
;
import
'ink_well.dart'
;
import
'material.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
typedef
void
TabSelectedIndexChanged
(
int
selectedIndex
);
typedef
void
TabSelectedIndexChanged
(
int
selectedIndex
);
...
@@ -403,6 +403,10 @@ class TabBarSelection {
...
@@ -403,6 +403,10 @@ class TabBarSelection {
int
_previousIndex
=
0
;
int
_previousIndex
=
0
;
}
}
/// A tab strip, consisting of several TabLabels and a TabBarSelection.
/// The TabBarSelection can be used to link this to a TabBarView.
///
/// Tabs must always have an ancestor Material object.
class
TabBar
extends
Scrollable
{
class
TabBar
extends
Scrollable
{
TabBar
({
TabBar
({
Key
key
,
Key
key
,
...
@@ -551,13 +555,13 @@ class _TabBarState extends ScrollableState<TabBar> {
...
@@ -551,13 +555,13 @@ class _TabBarState extends ScrollableState<TabBar> {
Widget
buildContent
(
BuildContext
context
)
{
Widget
buildContent
(
BuildContext
context
)
{
assert
(
config
.
labels
!=
null
&&
config
.
labels
.
isNotEmpty
);
assert
(
config
.
labels
!=
null
&&
config
.
labels
.
isNotEmpty
);
assert
(
Material
.
of
(
context
)
!=
null
);
ThemeData
themeData
=
Theme
.
of
(
context
);
ThemeData
themeData
=
Theme
.
of
(
context
);
Color
backgroundColor
=
themeData
.
primaryC
olor
;
Color
backgroundColor
=
Material
.
of
(
context
).
c
olor
;
Color
indicatorColor
=
themeData
.
accentColor
;
Color
indicatorColor
=
themeData
.
accentColor
;
if
(
indicatorColor
==
backgroundColor
)
{
if
(
indicatorColor
==
backgroundColor
)
indicatorColor
=
Colors
.
white
;
indicatorColor
=
Colors
.
white
;
}
TextStyle
textStyle
=
themeData
.
primaryTextTheme
.
body1
;
TextStyle
textStyle
=
themeData
.
primaryTextTheme
.
body1
;
IconThemeData
iconTheme
=
themeData
.
primaryIconTheme
;
IconThemeData
iconTheme
=
themeData
.
primaryIconTheme
;
...
@@ -571,7 +575,7 @@ class _TabBarState extends ScrollableState<TabBar> {
...
@@ -571,7 +575,7 @@ class _TabBarState extends ScrollableState<TabBar> {
textAndIcons
=
true
;
textAndIcons
=
true
;
}
}
Widget
content
=
new
IconTheme
(
Widget
content
s
=
new
IconTheme
(
data:
iconTheme
,
data:
iconTheme
,
child:
new
DefaultTextStyle
(
child:
new
DefaultTextStyle
(
style:
textStyle
,
style:
textStyle
,
...
@@ -594,23 +598,17 @@ class _TabBarState extends ScrollableState<TabBar> {
...
@@ -594,23 +598,17 @@ class _TabBarState extends ScrollableState<TabBar> {
);
);
if
(
config
.
isScrollable
)
{
if
(
config
.
isScrollable
)
{
content
=
new
SizeObserver
(
content
s
=
new
SizeObserver
(
onSizeChanged:
_handleViewportSizeChanged
,
onSizeChanged:
_handleViewportSizeChanged
,
child:
new
Viewport
(
child:
new
Viewport
(
scrollDirection:
ScrollDirection
.
horizontal
,
scrollDirection:
ScrollDirection
.
horizontal
,
scrollOffset:
new
Offset
(
scrollOffset
,
0.0
),
scrollOffset:
new
Offset
(
scrollOffset
,
0.0
),
child:
content
child:
content
s
)
)
);
);
}
}
return
new
AnimatedContainer
(
return
contents
;
decoration:
new
BoxDecoration
(
backgroundColor:
backgroundColor
),
duration:
kThemeChangeDuration
,
child:
content
);
}
}
}
}
...
...
packages/flutter/lib/src/material/theme_data.dart
View file @
ee802bfe
...
@@ -27,15 +27,7 @@ class ThemeData {
...
@@ -27,15 +27,7 @@ class ThemeData {
// Some users want the pre-multiplied color, others just want the opacity.
// Some users want the pre-multiplied color, others just want the opacity.
hintColor
=
brightness
==
ThemeBrightness
.
dark
?
const
Color
(
0x42FFFFFF
)
:
const
Color
(
0x4C000000
),
hintColor
=
brightness
==
ThemeBrightness
.
dark
?
const
Color
(
0x42FFFFFF
)
:
const
Color
(
0x4C000000
),
hintOpacity
=
brightness
==
ThemeBrightness
.
dark
?
0.26
:
0.30
,
hintOpacity
=
brightness
==
ThemeBrightness
.
dark
?
0.26
:
0.30
,
// TODO(eseidel): Where are highlight and selected colors documented?
highlightColor
=
brightness
==
ThemeBrightness
.
dark
?
const
Color
(
0x42FFFFFF
)
:
const
Color
(
0x1F000000
),
// I flipped highlight/selected to match the News app (which is clearly not quite Material)
// Gmail has an interesting behavior of showing selected darker until
// you click on a different drawer item when the first one loses its
// selected color and becomes lighter, the ink then fills to make the new
// click dark to match the previous (resting) selected state. States
// revert when you cancel the tap.
highlightColor
=
const
Color
(
0x33999999
),
selectedColor
=
const
Color
(
0x66999999
),
text
=
brightness
==
ThemeBrightness
.
dark
?
Typography
.
white
:
Typography
.
black
{
text
=
brightness
==
ThemeBrightness
.
dark
?
Typography
.
white
:
Typography
.
black
{
assert
(
brightness
!=
null
);
assert
(
brightness
!=
null
);
...
@@ -63,6 +55,13 @@ class ThemeData {
...
@@ -63,6 +55,13 @@ class ThemeData {
/// The brightness of the overall theme of the application. Used by widgets
/// The brightness of the overall theme of the application. Used by widgets
/// like buttons to determine what color to pick when not using the primary or
/// like buttons to determine what color to pick when not using the primary or
/// accent color.
/// accent color.
///
/// When the ThemeBrightness is dark, the canvas, card, and primary colors are
/// all dark. When the ThemeBrightness is light, the canvas and card colors
/// are bright, and the primary color's darkness varies as described by
/// primaryColorBrightness. The primaryColor does not contrast well with the
/// card and canvas colors when the brightness is dask; when the birghtness is
/// dark, use Colors.white or the accentColor for a contrasting color.
final
ThemeBrightness
brightness
;
final
ThemeBrightness
brightness
;
final
Map
<
int
,
Color
>
primarySwatch
;
final
Map
<
int
,
Color
>
primarySwatch
;
...
@@ -71,8 +70,9 @@ class ThemeData {
...
@@ -71,8 +70,9 @@ class ThemeData {
final
Color
dividerColor
;
final
Color
dividerColor
;
final
Color
hintColor
;
final
Color
hintColor
;
final
Color
highlightColor
;
final
Color
highlightColor
;
final
Color
selectedColor
;
final
double
hintOpacity
;
final
double
hintOpacity
;
/// Text with a color that contrasts with the card and canvas colors.
final
TextTheme
text
;
final
TextTheme
text
;
/// The background colour for major parts of the app (toolbars, tab bars, etc)
/// The background colour for major parts of the app (toolbars, tab bars, etc)
...
@@ -128,7 +128,6 @@ class ThemeData {
...
@@ -128,7 +128,6 @@ class ThemeData {
(
otherData
.
dividerColor
==
dividerColor
)
&&
(
otherData
.
dividerColor
==
dividerColor
)
&&
(
otherData
.
hintColor
==
hintColor
)
&&
(
otherData
.
hintColor
==
hintColor
)
&&
(
otherData
.
highlightColor
==
highlightColor
)
&&
(
otherData
.
highlightColor
==
highlightColor
)
&&
(
otherData
.
selectedColor
==
selectedColor
)
&&
(
otherData
.
hintOpacity
==
hintOpacity
)
&&
(
otherData
.
hintOpacity
==
hintOpacity
)
&&
(
otherData
.
text
==
text
)
&&
(
otherData
.
text
==
text
)
&&
(
otherData
.
primaryColorBrightness
==
primaryColorBrightness
)
&&
(
otherData
.
primaryColorBrightness
==
primaryColorBrightness
)
&&
...
@@ -143,7 +142,6 @@ class ThemeData {
...
@@ -143,7 +142,6 @@ class ThemeData {
value
=
37
*
value
+
dividerColor
.
hashCode
;
value
=
37
*
value
+
dividerColor
.
hashCode
;
value
=
37
*
value
+
hintColor
.
hashCode
;
value
=
37
*
value
+
hintColor
.
hashCode
;
value
=
37
*
value
+
highlightColor
.
hashCode
;
value
=
37
*
value
+
highlightColor
.
hashCode
;
value
=
37
*
value
+
selectedColor
.
hashCode
;
value
=
37
*
value
+
hintOpacity
.
hashCode
;
value
=
37
*
value
+
hintOpacity
.
hashCode
;
value
=
37
*
value
+
text
.
hashCode
;
value
=
37
*
value
+
text
.
hashCode
;
value
=
37
*
value
+
primaryColorBrightness
.
hashCode
;
value
=
37
*
value
+
primaryColorBrightness
.
hashCode
;
...
...
packages/flutter/lib/src/material/tool_bar.dart
View file @
ee802bfe
...
@@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
...
@@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
import
'constants.dart'
;
import
'constants.dart'
;
import
'icon_theme.dart'
;
import
'icon_theme.dart'
;
import
'icon_theme_data.dart'
;
import
'icon_theme_data.dart'
;
import
'
shadows
.dart'
;
import
'
material
.dart'
;
import
'tabs.dart'
;
import
'tabs.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
import
'typography.dart'
;
import
'typography.dart'
;
...
@@ -36,9 +36,9 @@ class ToolBar extends StatelessComponent {
...
@@ -36,9 +36,9 @@ class ToolBar extends StatelessComponent {
final
TextTheme
textTheme
;
final
TextTheme
textTheme
;
final
EdgeDims
padding
;
final
EdgeDims
padding
;
ToolBar
withPadding
(
EdgeDims
newPadding
)
{
ToolBar
withPadding
(
EdgeDims
newPadding
,
{
Key
fallbackKey
}
)
{
return
new
ToolBar
(
return
new
ToolBar
(
key:
key
,
key:
key
??
fallbackKey
,
left:
left
,
left:
left
,
center:
center
,
center:
center
,
right:
right
,
right:
right
,
...
@@ -67,52 +67,63 @@ class ToolBar extends StatelessComponent {
...
@@ -67,52 +67,63 @@ class ToolBar extends StatelessComponent {
sideStyle
??=
primaryTextTheme
.
body2
;
sideStyle
??=
primaryTextTheme
.
body2
;
}
}
List
<
Widget
>
children
=
new
List
<
Widget
>();
final
List
<
Widget
>
firstRow
=
<
Widget
>[];
if
(
left
!=
null
)
if
(
left
!=
null
)
children
.
add
(
left
);
firstRow
.
add
(
left
);
firstRow
.
add
(
children
.
add
(
new
Flexible
(
new
Flexible
(
child:
new
Padding
(
child:
new
Padding
(
child:
center
!=
null
?
new
DefaultTextStyle
(
child:
center
,
style:
centerStyle
)
:
null
,
padding:
new
EdgeDims
.
only
(
left:
24.0
)
,
padding:
new
EdgeDims
.
only
(
left:
24.0
)
child:
center
!=
null
?
new
DefaultTextStyle
(
style:
centerStyle
,
child:
center
)
:
null
)
)
)
)
);
);
if
(
right
!=
null
)
if
(
right
!=
null
)
children
.
addAll
(
right
);
firstRow
.
addAll
(
right
);
final
List
<
Widget
>
columnChildren
=
<
Widget
>[
final
List
<
Widget
>
rows
=
<
Widget
>[
new
Container
(
height:
kToolBarHeight
,
child:
new
Row
(
children
))
new
Container
(
height:
kToolBarHeight
,
child:
new
DefaultTextStyle
(
style:
sideStyle
,
child:
new
Row
(
firstRow
)
)
)
];
];
if
(
bottom
!=
null
)
{
if
(
bottom
!=
null
)
rows
.
add
(
columnChildren
.
add
(
new
DefaultTextStyle
(
new
DefaultTextStyle
(
style:
centerStyle
,
style:
centerStyle
,
child:
new
Container
(
height:
kExtendedToolBarHeight
-
kToolBarHeight
,
child:
bottom
)
child:
new
Container
(
));
height:
kExtendedToolBarHeight
-
kToolBarHeight
,
child:
bottom
)
)
);
}
if
(
tabBar
!=
null
)
if
(
tabBar
!=
null
)
columnChildren
.
add
(
tabBar
);
rows
.
add
(
tabBar
);
EdgeDims
combinedPadding
=
new
EdgeDims
.
symmetric
(
horizontal:
8.0
);
if
(
padding
!=
null
)
combinedPadding
+=
padding
;
Widget
content
=
new
AnimatedContainer
(
Widget
contents
=
new
Material
(
duration:
kThemeChangeDuration
,
color:
color
,
padding:
new
EdgeDims
.
symmetric
(
horizontal:
8.0
),
elevation:
elevation
,
decoration:
new
BoxDecoration
(
child:
new
Container
(
backgroundColor:
color
,
padding:
combinedPadding
,
boxShadow:
elevationToShadow
[
elevation
]
child:
new
Column
(
),
rows
,
child:
new
DefaultTextStyle
(
justifyContent:
FlexJustifyContent
.
collapse
style:
sideStyle
,
)
child:
new
Container
(
padding:
padding
,
child:
new
Column
(
columnChildren
,
justifyContent:
FlexJustifyContent
.
collapse
))
)
)
);
);
if
(
iconThemeData
!=
null
)
if
(
iconThemeData
!=
null
)
content
=
new
IconTheme
(
data:
iconThemeData
,
child:
content
);
contents
=
new
IconTheme
(
data:
iconThemeData
,
child:
contents
);
return
content
;
return
contents
;
}
}
}
}
packages/flutter/lib/src/widgets/framework.dart
View file @
ee802bfe
...
@@ -386,8 +386,17 @@ abstract class State<T extends StatefulComponent> {
...
@@ -386,8 +386,17 @@ abstract class State<T extends StatefulComponent> {
_element
.
markNeedsBuild
();
_element
.
markNeedsBuild
();
}
}
/// Called when this object is removed from the tree. Override this to clean
/// Called when this object is removed from the tree.
/// up any resources allocated by this object.
/// The object might momentarily be reattached to the tree elsewhere.
///
/// Use this to clean up any links between this state and other
/// elements in the tree (e.g. if you have provided an ancestor with
/// a pointer to a descendant's renderObject).
void
deactivate
()
{
}
/// Called when this object is removed from the tree permanently.
/// Override this to clean up any resources allocated by this
/// object.
///
///
/// If you override this, make sure to end your method with a call to
/// If you override this, make sure to end your method with a call to
/// super.dispose().
/// super.dispose().
...
@@ -405,6 +414,11 @@ abstract class State<T extends StatefulComponent> {
...
@@ -405,6 +414,11 @@ abstract class State<T extends StatefulComponent> {
/// provides the set of inherited widgets for this location in the tree.
/// provides the set of inherited widgets for this location in the tree.
Widget
build
(
BuildContext
context
);
Widget
build
(
BuildContext
context
);
/// Called when an Inherited widget in the ancestor chain has changed. Usually
/// there is nothing to do here; whenever this is called, build() is also
/// called.
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
}
String
toString
()
{
String
toString
()
{
final
List
<
String
>
data
=
<
String
>[];
final
List
<
String
>
data
=
<
String
>[];
debugFillDescription
(
data
);
debugFillDescription
(
data
);
...
@@ -540,6 +554,7 @@ abstract class BuildContext {
...
@@ -540,6 +554,7 @@ abstract class BuildContext {
InheritedWidget
inheritFromWidgetOfType
(
Type
targetType
);
InheritedWidget
inheritFromWidgetOfType
(
Type
targetType
);
Widget
ancestorWidgetOfType
(
Type
targetType
);
Widget
ancestorWidgetOfType
(
Type
targetType
);
State
ancestorStateOfType
(
Type
targetType
);
State
ancestorStateOfType
(
Type
targetType
);
RenderObject
ancestorRenderObjectOfType
(
Type
targetType
);
void
visitAncestorElements
(
bool
visitor
(
Element
element
));
void
visitAncestorElements
(
bool
visitor
(
Element
element
));
void
visitChildElements
(
void
visitor
(
Element
element
));
void
visitChildElements
(
void
visitor
(
Element
element
));
}
}
...
@@ -777,7 +792,7 @@ abstract class Element<T extends Widget> implements BuildContext {
...
@@ -777,7 +792,7 @@ abstract class Element<T extends Widget> implements BuildContext {
assert
(
child
.
_parent
==
this
);
assert
(
child
.
_parent
==
this
);
child
.
_parent
=
null
;
child
.
_parent
=
null
;
child
.
detachRenderObject
();
child
.
detachRenderObject
();
_inactiveElements
.
add
(
child
);
_inactiveElements
.
add
(
child
);
// this eventually calls child.deactivate()
}
}
void
deactivate
()
{
void
deactivate
()
{
...
@@ -839,13 +854,24 @@ abstract class Element<T extends Widget> implements BuildContext {
...
@@ -839,13 +854,24 @@ abstract class Element<T extends Widget> implements BuildContext {
return
statefulAncestor
?.
state
;
return
statefulAncestor
?.
state
;
}
}
RenderObject
ancestorRenderObjectOfType
(
Type
targetType
)
{
Element
ancestor
=
_parent
;
while
(
ancestor
!=
null
)
{
if
(
ancestor
is
RenderObjectElement
&&
ancestor
.
renderObject
.
runtimeType
==
targetType
)
break
;
ancestor
=
ancestor
.
_parent
;
}
RenderObjectElement
renderObjectAncestor
=
ancestor
;
return
renderObjectAncestor
?.
renderObject
;
}
void
visitAncestorElements
(
bool
visitor
(
Element
element
))
{
void
visitAncestorElements
(
bool
visitor
(
Element
element
))
{
Element
ancestor
=
_parent
;
Element
ancestor
=
_parent
;
while
(
ancestor
!=
null
&&
visitor
(
ancestor
))
while
(
ancestor
!=
null
&&
visitor
(
ancestor
))
ancestor
=
ancestor
.
_parent
;
ancestor
=
ancestor
.
_parent
;
}
}
void
dependenciesChanged
()
{
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
assert
(
false
);
assert
(
false
);
}
}
...
@@ -1024,7 +1050,7 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
...
@@ -1024,7 +1050,7 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
/// Called by rebuild() after the appropriate checks have been made.
/// Called by rebuild() after the appropriate checks have been made.
void
performRebuild
();
void
performRebuild
();
void
dependenciesChanged
()
{
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
markNeedsBuild
();
markNeedsBuild
();
}
}
...
@@ -1169,6 +1195,11 @@ class StatefulComponentElement<T extends StatefulComponent, U extends State<T>>
...
@@ -1169,6 +1195,11 @@ class StatefulComponentElement<T extends StatefulComponent, U extends State<T>>
rebuild
();
rebuild
();
}
}
void
deactivate
()
{
_state
.
deactivate
();
super
.
deactivate
();
}
void
unmount
()
{
void
unmount
()
{
super
.
unmount
();
super
.
unmount
();
_state
.
dispose
();
_state
.
dispose
();
...
@@ -1183,6 +1214,11 @@ class StatefulComponentElement<T extends StatefulComponent, U extends State<T>>
...
@@ -1183,6 +1214,11 @@ class StatefulComponentElement<T extends StatefulComponent, U extends State<T>>
_state
=
null
;
_state
=
null
;
}
}
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
super
.
dependenciesChanged
(
affectedWidgetType
);
_state
.
dependenciesChanged
(
affectedWidgetType
);
}
void
debugFillDescription
(
List
<
String
>
description
)
{
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
super
.
debugFillDescription
(
description
);
if
(
state
!=
null
)
if
(
state
!=
null
)
...
@@ -1252,7 +1288,7 @@ class InheritedElement extends ProxyElement<InheritedWidget> {
...
@@ -1252,7 +1288,7 @@ class InheritedElement extends ProxyElement<InheritedWidget> {
void
notifyChildren
(
Element
child
)
{
void
notifyChildren
(
Element
child
)
{
if
(
child
.
_dependencies
!=
null
&&
if
(
child
.
_dependencies
!=
null
&&
child
.
_dependencies
.
contains
(
ourRuntimeType
))
{
child
.
_dependencies
.
contains
(
ourRuntimeType
))
{
child
.
dependenciesChanged
();
child
.
dependenciesChanged
(
ourRuntimeType
);
}
}
if
(
child
.
runtimeType
!=
ourRuntimeType
)
if
(
child
.
runtimeType
!=
ourRuntimeType
)
child
.
visitChildren
(
notifyChildren
);
child
.
visitChildren
(
notifyChildren
);
...
...
packages/flutter/lib/src/widgets/notification_listener.dart
0 → 100644
View file @
ee802bfe
// 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
'framework.dart'
;
/// Return true to cancel the notification bubbling.
typedef
bool
NotificationListenerCallback
<
T
extends
Notification
>(
T
notification
);
abstract
class
Notification
{
void
dispatch
(
BuildContext
target
)
{
target
.
visitAncestorElements
((
Element
element
)
{
if
(
element
is
StatelessComponentElement
&&
element
.
widget
is
NotificationListener
)
{
final
NotificationListener
widget
=
element
.
widget
;
if
(
widget
.
_dispatch
(
this
))
return
false
;
}
return
true
;
});
}
}
class
NotificationListener
<
T
extends
Notification
>
extends
StatelessComponent
{
NotificationListener
({
Key
key
,
this
.
child
,
this
.
onNotification
})
:
super
(
key:
key
);
final
Widget
child
;
final
NotificationListenerCallback
<
T
>
onNotification
;
bool
_dispatch
(
Notification
notification
)
{
if
(
onNotification
!=
null
&&
notification
is
T
)
return
onNotification
(
notification
);
return
false
;
}
Widget
build
(
BuildContext
context
)
=>
child
;
}
/// Indicates that the layout of one of the descendants of the object receiving
/// this notification has changed in some way, and that therefore any
/// assumptions about that layout are no longer valid.
///
/// Useful if, for instance, you're trying to align multiple descendants.
///
/// Be aware that in the widgets library, only the [Scrollable] classes dispatch
/// this notification. (Transitions, in particular, do not.) Changing one's
/// layout in one's build function does not cause this notification to be
/// dispatched automatically. If an ancestor expects to be notified for any
/// layout change, make sure you only use widgets that either never change
/// layout, or that do notify their ancestors when appropriate.
class
LayoutChangedNotification
extends
Notification
{
}
packages/flutter/lib/src/widgets/scrollable.dart
View file @
ee802bfe
...
@@ -16,6 +16,7 @@ import 'framework.dart';
...
@@ -16,6 +16,7 @@ import 'framework.dart';
import
'gesture_detector.dart'
;
import
'gesture_detector.dart'
;
import
'homogeneous_viewport.dart'
;
import
'homogeneous_viewport.dart'
;
import
'mixed_viewport.dart'
;
import
'mixed_viewport.dart'
;
import
'notification_listener.dart'
;
import
'page_storage.dart'
;
import
'page_storage.dart'
;
// The gesture velocity properties are pixels/second, config min,max limits are pixels/ms
// The gesture velocity properties are pixels/second, config min,max limits are pixels/ms
...
@@ -50,6 +51,8 @@ abstract class Scrollable extends StatefulComponent {
...
@@ -50,6 +51,8 @@ abstract class Scrollable extends StatefulComponent {
final
ScrollListener
onScrollEnd
;
final
ScrollListener
onScrollEnd
;
final
SnapOffsetCallback
snapOffsetCallback
;
final
SnapOffsetCallback
snapOffsetCallback
;
final
double
snapAlignmentOffset
;
final
double
snapAlignmentOffset
;
ScrollableState
createState
();
}
}
abstract
class
ScrollableState
<
T
extends
Scrollable
>
extends
State
<
T
>
{
abstract
class
ScrollableState
<
T
extends
Scrollable
>
extends
State
<
T
>
{
...
@@ -180,6 +183,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -180,6 +183,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
_scrollOffset
=
newScrollOffset
;
_scrollOffset
=
newScrollOffset
;
});
});
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
new
ScrollNotification
(
this
,
_scrollOffset
).
dispatch
(
context
);
dispatchOnScroll
();
dispatchOnScroll
();
}
}
...
@@ -271,6 +275,12 @@ ScrollableState findScrollableAncestor(BuildContext context) {
...
@@ -271,6 +275,12 @@ ScrollableState findScrollableAncestor(BuildContext context) {
return
result
;
return
result
;
}
}
class
ScrollNotification
extends
Notification
{
ScrollNotification
(
this
.
scrollable
,
this
.
position
);
final
ScrollableState
scrollable
;
final
double
position
;
}
Future
ensureWidgetIsVisible
(
BuildContext
context
,
{
Duration
duration
,
Curve
curve
})
{
Future
ensureWidgetIsVisible
(
BuildContext
context
,
{
Duration
duration
,
Curve
curve
})
{
assert
(
context
.
findRenderObject
()
is
RenderBox
);
assert
(
context
.
findRenderObject
()
is
RenderBox
);
// TODO(abarth): This function doesn't handle nested scrollable widgets.
// TODO(abarth): This function doesn't handle nested scrollable widgets.
...
...
packages/flutter/lib/widgets.dart
View file @
ee802bfe
...
@@ -25,6 +25,7 @@ export 'src/widgets/mimic.dart';
...
@@ -25,6 +25,7 @@ export 'src/widgets/mimic.dart';
export
'src/widgets/mixed_viewport.dart'
;
export
'src/widgets/mixed_viewport.dart'
;
export
'src/widgets/modal_barrier.dart'
;
export
'src/widgets/modal_barrier.dart'
;
export
'src/widgets/navigator.dart'
;
export
'src/widgets/navigator.dart'
;
export
'src/widgets/notification_listener.dart'
;
export
'src/widgets/overlay.dart'
;
export
'src/widgets/overlay.dart'
;
export
'src/widgets/page_storage.dart'
;
export
'src/widgets/page_storage.dart'
;
export
'src/widgets/placeholder.dart'
;
export
'src/widgets/placeholder.dart'
;
...
...
packages/unit/test/animation/scheduler_test.dart
View file @
ee802bfe
...
@@ -2,6 +2,10 @@ import 'package:flutter/animation.dart';
...
@@ -2,6 +2,10 @@ import 'package:flutter/animation.dart';
import
'package:test/test.dart'
;
import
'package:test/test.dart'
;
void
main
(
)
{
void
main
(
)
{
test
(
"Check for a time dilation being in effect"
,
()
{
expect
(
timeDilation
,
equals
(
1.0
));
});
test
(
"Can cancel queued callback"
,
()
{
test
(
"Can cancel queued callback"
,
()
{
int
secondId
;
int
secondId
;
...
...
packages/unit/test/widget/date_picker_test.dart
View file @
ee802bfe
...
@@ -11,16 +11,18 @@ void main() {
...
@@ -11,16 +11,18 @@ void main() {
testWidgets
((
WidgetTester
tester
)
{
testWidgets
((
WidgetTester
tester
)
{
DateTime
currentValue
;
DateTime
currentValue
;
Widget
widget
=
new
Block
(<
Widget
>[
Widget
widget
=
new
Material
(
new
DatePicker
(
child:
new
Block
(<
Widget
>[
selectedDate:
new
DateTime
.
utc
(
2015
,
6
,
9
,
7
,
12
),
new
DatePicker
(
firstDate:
new
DateTime
.
utc
(
2013
),
selectedDate:
new
DateTime
.
utc
(
2015
,
6
,
9
,
7
,
12
),
lastDate:
new
DateTime
.
utc
(
2018
),
firstDate:
new
DateTime
.
utc
(
2013
),
onChanged:
(
DateTime
dateTime
)
{
lastDate:
new
DateTime
.
utc
(
2018
),
currentValue
=
dateTime
;
onChanged:
(
DateTime
dateTime
)
{
}
currentValue
=
dateTime
;
)
}
]);
)
])
);
tester
.
pumpWidget
(
widget
);
tester
.
pumpWidget
(
widget
);
...
...
packages/unit/test/widget/heroes_test.dart
View file @
ee802bfe
...
@@ -11,18 +11,22 @@ import 'test_matchers.dart';
...
@@ -11,18 +11,22 @@ import 'test_matchers.dart';
Key
firstKey
=
new
Key
(
'first'
);
Key
firstKey
=
new
Key
(
'first'
);
Key
secondKey
=
new
Key
(
'second'
);
Key
secondKey
=
new
Key
(
'second'
);
final
Map
<
String
,
RouteBuilder
>
routes
=
<
String
,
RouteBuilder
>{
final
Map
<
String
,
RouteBuilder
>
routes
=
<
String
,
RouteBuilder
>{
'/'
:
(
RouteArguments
args
)
=>
new
Block
([
'/'
:
(
RouteArguments
args
)
=>
new
Material
(
new
Container
(
height:
100.0
,
width:
100.0
),
child:
new
Block
([
new
Card
(
child:
new
Hero
(
tag:
'a'
,
child:
new
Container
(
height:
100.0
,
width:
100.0
,
key:
firstKey
))),
new
Container
(
height:
100.0
,
width:
100.0
),
new
Container
(
height:
100.0
,
width:
100.0
),
new
Card
(
child:
new
Hero
(
tag:
'a'
,
child:
new
Container
(
height:
100.0
,
width:
100.0
,
key:
firstKey
))),
new
FlatButton
(
child:
new
Text
(
'button'
),
onPressed:
()
=>
Navigator
.
pushNamed
(
args
.
context
,
'/two'
)),
new
Container
(
height:
100.0
,
width:
100.0
),
]),
new
FlatButton
(
child:
new
Text
(
'button'
),
onPressed:
()
=>
Navigator
.
pushNamed
(
args
.
context
,
'/two'
)),
'/two'
:
(
RouteArguments
args
)
=>
new
Block
([
])
new
Container
(
height:
150.0
,
width:
150.0
),
),
new
Card
(
child:
new
Hero
(
tag:
'a'
,
child:
new
Container
(
height:
150.0
,
width:
150.0
,
key:
secondKey
))),
'/two'
:
(
RouteArguments
args
)
=>
new
Material
(
new
Container
(
height:
150.0
,
width:
150.0
),
child:
new
Block
([
new
FlatButton
(
child:
new
Text
(
'button'
),
onPressed:
()
=>
Navigator
.
pop
(
args
.
context
)),
new
Container
(
height:
150.0
,
width:
150.0
),
]),
new
Card
(
child:
new
Hero
(
tag:
'a'
,
child:
new
Container
(
height:
150.0
,
width:
150.0
,
key:
secondKey
))),
new
Container
(
height:
150.0
,
width:
150.0
),
new
FlatButton
(
child:
new
Text
(
'button'
),
onPressed:
()
=>
Navigator
.
pop
(
args
.
context
)),
])
),
};
};
void
main
(
)
{
void
main
(
)
{
...
...
packages/unit/test/widget/tabs_test.dart
View file @
ee802bfe
...
@@ -10,10 +10,12 @@ import 'package:test/test.dart';
...
@@ -10,10 +10,12 @@ import 'package:test/test.dart';
TabBarSelection
selection
;
TabBarSelection
selection
;
Widget
buildFrame
(
{
List
<
String
>
tabs
,
bool
isScrollable:
false
})
{
Widget
buildFrame
(
{
List
<
String
>
tabs
,
bool
isScrollable:
false
})
{
return
new
TabBar
(
return
new
Material
(
labels:
tabs
.
map
((
String
tab
)
=>
new
TabLabel
(
text:
tab
)).
toList
(),
child:
new
TabBar
(
selection:
selection
,
labels:
tabs
.
map
((
String
tab
)
=>
new
TabLabel
(
text:
tab
)).
toList
(),
isScrollable:
isScrollable
selection:
selection
,
isScrollable:
isScrollable
)
);
);
}
}
...
...
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