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
a2b8f8b9
Commit
a2b8f8b9
authored
Dec 04, 2015
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #721 from abarth/ink_response
Improve material ink response
parents
dc907830
0608a02a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
132 additions
and
110 deletions
+132
-110
ink_well.dart
packages/flutter/lib/src/material/ink_well.dart
+50
-69
material.dart
packages/flutter/lib/src/material/material.dart
+62
-40
theme_data.dart
packages/flutter/lib/src/material/theme_data.dart
+20
-1
No files found.
packages/flutter/lib/src/material/ink_well.dart
View file @
a2b8f8b9
...
...
@@ -16,7 +16,9 @@ class InkResponse extends StatefulComponent {
this
.
onTap
,
this
.
onDoubleTap
,
this
.
onLongPress
,
this
.
onHighlightChanged
this
.
onHighlightChanged
,
this
.
containedInWell
:
false
,
this
.
highlightShape
:
Shape
.
circle
})
:
super
(
key:
key
);
final
Widget
child
;
...
...
@@ -24,16 +26,44 @@ class InkResponse extends StatefulComponent {
final
GestureTapCallback
onDoubleTap
;
final
GestureLongPressCallback
onLongPress
;
final
ValueChanged
<
bool
>
onHighlightChanged
;
final
bool
containedInWell
;
final
Shape
highlightShape
;
_InkResponseState
createState
()
=>
new
_InkResponseState
<
InkResponse
>();
}
class
_InkResponseState
<
T
extends
InkResponse
>
extends
State
<
T
>
{
bool
get
containedInWell
=>
false
;
Set
<
InkSplash
>
_splashes
;
InkSplash
_currentSplash
;
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
).
highlightAt
(
referenceBox:
referenceBox
,
color:
Theme
.
of
(
context
).
highlightColor
,
shape:
config
.
highlightShape
,
onRemoved:
()
{
assert
(
_lastHighlight
!=
null
);
_lastHighlight
=
null
;
}
);
}
else
{
_lastHighlight
.
activate
();
}
}
else
{
_lastHighlight
.
deactivate
();
}
if
(
config
.
onHighlightChanged
!=
null
)
config
.
onHighlightChanged
(
value
!=
null
);
}
void
_handleTapDown
(
Point
position
)
{
RenderBox
referenceBox
=
context
.
findRenderObject
();
...
...
@@ -42,7 +72,8 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
splash
=
Material
.
of
(
context
).
splashAt
(
referenceBox:
referenceBox
,
position:
referenceBox
.
globalToLocal
(
position
),
containedInWell:
containedInWell
,
color:
Theme
.
of
(
context
).
splashColor
,
containedInWell:
config
.
containedInWell
,
onRemoved:
()
{
if
(
_splashes
!=
null
)
{
assert
(
_splashes
.
contains
(
splash
));
...
...
@@ -55,11 +86,13 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
_splashes
??=
new
Set
<
InkSplash
>();
_splashes
.
add
(
splash
);
_currentSplash
=
splash
;
updateHighlight
(
true
);
}
void
_handleTap
()
{
_currentSplash
?.
confirm
();
_currentSplash
=
null
;
updateHighlight
(
false
);
if
(
config
.
onTap
!=
null
)
config
.
onTap
();
}
...
...
@@ -67,6 +100,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
void
_handleTapCancel
()
{
_currentSplash
?.
cancel
();
_currentSplash
=
null
;
updateHighlight
(
false
);
}
void
_handleDoubleTap
()
{
...
...
@@ -92,9 +126,16 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
_currentSplash
=
null
;
}
assert
(
_currentSplash
==
null
);
_lastHighlight
?.
dispose
();
_lastHighlight
=
null
;
super
.
deactivate
();
}
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
if
(
affectedWidgetType
==
Theme
&&
_lastHighlight
!=
null
)
_lastHighlight
.
color
=
Theme
.
of
(
context
).
highlightColor
;
}
Widget
build
(
BuildContext
context
)
{
final
bool
enabled
=
config
.
onTap
!=
null
||
config
.
onDoubleTap
!=
null
||
config
.
onLongPress
!=
null
;
return
new
GestureDetector
(
...
...
@@ -120,75 +161,15 @@ class InkWell extends InkResponse {
GestureTapCallback
onTap
,
GestureTapCallback
onDoubleTap
,
GestureLongPressCallback
onLongPress
,
this
.
onHighlightChanged
ValueChanged
<
bool
>
onHighlightChanged
})
:
super
(
key:
key
,
child:
child
,
onTap:
onTap
,
onDoubleTap:
onDoubleTap
,
onLongPress:
onLongPress
onLongPress:
onLongPress
,
onHighlightChanged:
onHighlightChanged
,
containedInWell:
true
,
highlightShape:
Shape
.
rectangle
);
final
ValueChanged
<
bool
>
onHighlightChanged
;
_InkWellState
createState
()
=>
new
_InkWellState
();
}
class
_InkWellState
extends
_InkResponseState
<
InkWell
>
{
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
{
_lastHighlight
.
deactivate
();
}
if
(
config
.
onHighlightChanged
!=
null
)
config
.
onHighlightChanged
(
value
!=
null
);
}
void
_handleTapDown
(
Point
position
)
{
super
.
_handleTapDown
(
position
);
updateHighlight
(
true
);
}
void
_handleTap
()
{
super
.
_handleTap
();
updateHighlight
(
false
);
}
void
_handleTapCancel
()
{
super
.
_handleTapCancel
();
updateHighlight
(
false
);
}
void
deactivate
()
{
_lastHighlight
?.
dispose
();
_lastHighlight
=
null
;
super
.
deactivate
();
}
void
dependenciesChanged
(
Type
affectedWidgetType
)
{
if
(
affectedWidgetType
==
Theme
&&
_lastHighlight
!=
null
)
_lastHighlight
.
color
=
Theme
.
of
(
context
).
highlightColor
;
}
}
packages/flutter/lib/src/material/material.dart
View file @
a2b8f8b9
...
...
@@ -58,10 +58,10 @@ abstract class MaterialInkController {
/// 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
});
InkSplash
splashAt
({
RenderBox
referenceBox
,
Point
position
,
Color
color
,
bool
containedInWell
,
VoidCallback
onRemoved
});
/// Begin a highlight, coincident with the referenceBox.
InkHighlight
highlight
RectAt
({
RenderBox
referenceBox
,
Color
color
,
VoidCallback
onRemoved
});
InkHighlight
highlight
At
({
RenderBox
referenceBox
,
Color
color
,
Shape
shape:
Shape
.
rectangle
,
VoidCallback
onRemoved
});
/// Add an arbitrary InkFeature to this InkController.
void
addInkFeature
(
InkFeature
feature
);
...
...
@@ -156,14 +156,12 @@ class _MaterialState extends State<Material> {
}
}
const
Duration
_kHighlightFadeDuration
=
const
Duration
(
milliseconds:
100
);
const
Duration
_kHighlightFadeDuration
=
const
Duration
(
milliseconds:
200
);
const
Duration
_kUnconfirmedSplashDuration
=
const
Duration
(
seconds:
1
);
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
_kSplashConfirmedVelocity
=
1.0
;
// 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
);
...
...
@@ -175,7 +173,13 @@ class RenderInkFeatures extends RenderProxyBox implements MaterialInkController
final
List
<
InkFeature
>
_inkFeatures
=
<
InkFeature
>[];
InkSplash
splashAt
({
RenderBox
referenceBox
,
Point
position
,
bool
containedInWell
,
VoidCallback
onRemoved
})
{
InkSplash
splashAt
({
RenderBox
referenceBox
,
Point
position
,
Color
color
,
bool
containedInWell
,
VoidCallback
onRemoved
})
{
double
radius
;
if
(
containedInWell
)
{
radius
=
_getSplashTargetSize
(
referenceBox
.
size
,
position
);
...
...
@@ -186,8 +190,10 @@ class RenderInkFeatures extends RenderProxyBox implements MaterialInkController
renderer:
this
,
referenceBox:
referenceBox
,
position:
position
,
color:
color
,
targetRadius:
radius
,
clipToReferenceBox:
containedInWell
,
repositionToReferenceBox:
!
containedInWell
,
onRemoved:
onRemoved
);
addInkFeature
(
splash
);
...
...
@@ -202,11 +208,17 @@ class RenderInkFeatures extends RenderProxyBox implements MaterialInkController
return
math
.
max
(
math
.
max
(
d1
,
d2
),
math
.
max
(
d3
,
d4
)).
ceilToDouble
();
}
InkHighlight
highlightRectAt
({
RenderBox
referenceBox
,
Color
color
,
VoidCallback
onRemoved
})
{
InkHighlight
highlightAt
({
RenderBox
referenceBox
,
Color
color
,
Shape
shape:
Shape
.
rectangle
,
VoidCallback
onRemoved
})
{
_InkHighlight
highlight
=
new
_InkHighlight
(
renderer:
this
,
referenceBox:
referenceBox
,
color:
color
,
shape:
shape
,
onRemoved:
onRemoved
);
addInkFeature
(
highlight
);
...
...
@@ -303,45 +315,45 @@ class _InkSplash extends InkFeature implements InkSplash {
RenderInkFeatures
renderer
,
RenderBox
referenceBox
,
this
.
position
,
this
.
color
,
this
.
targetRadius
,
this
.
clipToReferenceBox
,
this
.
repositionToReferenceBox
,
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
)
variable:
new
AnimatedValue
<
double
>(
_kSplashInitialSize
,
end:
targetRadius
),
duration:
_kUnconfirmedSplashDuration
)..
addListener
(
renderer
.
markNeedsPaint
)
..
play
();
_alpha
=
new
ValuePerformance
<
int
>(
variable:
new
AnimatedIntValue
(
color
.
alpha
,
end:
0
),
duration:
_kHighlightFadeDuration
)..
addListener
(
_handleAlphaChange
);
}
final
Point
position
;
final
Color
color
;
final
double
targetRadius
;
final
bool
clipToReferenceBox
;
final
bool
repositionToReferenceBox
;
double
_pinnedRadius
;
ValuePerformance
<
double
>
_radius
;
ValuePerformance
<
int
>
_alpha
;
void
confirm
()
{
_updateVelocity
(
_kSplashConfirmedVelocity
);
int
duration
=
(
targetRadius
/
_kSplashConfirmedVelocity
).
floor
();
_radius
.
duration
=
new
Duration
(
milliseconds:
duration
);
_radius
.
play
();
_alpha
.
play
();
}
void
cancel
()
{
_updateVelocity
(
_kSplashCanceledVelocity
);
_pinnedRadius
=
_radius
.
value
;
_alpha
.
play
();
}
void
_updateVelocity
(
double
velocity
)
{
int
duration
=
(
targetRadius
/
velocity
).
floor
();
_radius
.
duration
=
new
Duration
(
milliseconds:
duration
);
_radius
.
play
();
}
void
_handleRadiusChange
()
{
if
(
_radius
.
value
==
targetRadius
)
void
_handleAlphaChange
()
{
if
(
_alpha
.
value
==
_alpha
.
variable
.
end
)
dispose
();
else
renderer
.
markNeedsPaint
();
...
...
@@ -349,27 +361,31 @@ class _InkSplash extends InkFeature implements InkSplash {
void
dispose
()
{
_radius
.
stop
();
_alpha
.
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
;
Paint
paint
=
new
Paint
()..
color
=
color
.
withAlpha
(
_alpha
.
value
);
Point
center
=
position
;
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
);
if
(
repositionToReferenceBox
)
center
=
Point
.
lerp
(
center
,
Point
.
origin
,
_radius
.
progress
);
canvas
.
drawCircle
(
center
,
_radius
.
value
,
paint
);
canvas
.
restore
();
}
else
{
if
(
clipToReferenceBox
)
{
canvas
.
save
();
canvas
.
clipRect
(
originOffset
.
toPoint
()
&
referenceBox
.
size
);
}
canvas
.
drawCircle
(
position
+
originOffset
,
radius
,
paint
);
if
(
repositionToReferenceBox
)
center
=
Point
.
lerp
(
center
,
referenceBox
.
size
.
center
(
Point
.
origin
),
_radius
.
progress
);
canvas
.
drawCircle
(
center
+
originOffset
,
_radius
.
value
,
paint
);
if
(
clipToReferenceBox
)
canvas
.
restore
();
}
...
...
@@ -381,15 +397,12 @@ class _InkHighlight extends InkFeature implements InkHighlight {
RenderInkFeatures
renderer
,
RenderBox
referenceBox
,
Color
color
,
this
.
shape
,
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
),
variable:
new
AnimatedIntValue
(
0
,
end:
color
.
alpha
),
duration:
_kHighlightFadeDuration
)..
addListener
(
_handleAlphaChange
)
..
play
();
...
...
@@ -404,6 +417,8 @@ class _InkHighlight extends InkFeature implements InkHighlight {
renderer
.
markNeedsPaint
();
}
final
Shape
shape
;
bool
get
active
=>
_active
;
bool
_active
=
true
;
ValuePerformance
<
int
>
_alpha
;
...
...
@@ -430,16 +445,23 @@ class _InkHighlight extends InkFeature implements InkHighlight {
super
.
dispose
();
}
void
_paintHighlight
(
Canvas
canvas
,
Rect
rect
,
paint
)
{
if
(
shape
==
Shape
.
rectangle
)
canvas
.
drawRect
(
rect
,
paint
);
else
canvas
.
drawCircle
(
rect
.
center
,
_kDefaultSplashRadius
,
paint
);
}
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
);
_paintHighlight
(
canvas
,
Point
.
origin
&
referenceBox
.
size
,
paint
);
canvas
.
restore
();
}
else
{
canvas
.
drawRect
(
originOffset
.
toPoint
()
&
referenceBox
.
size
,
paint
);
_paintHighlight
(
canvas
,
originOffset
.
toPoint
()
&
referenceBox
.
size
,
paint
);
}
}
...
...
packages/flutter/lib/src/material/theme_data.dart
View file @
a2b8f8b9
...
...
@@ -10,6 +10,23 @@ import 'typography.dart';
enum
ThemeBrightness
{
dark
,
light
}
// Deriving these values is black magic. The spec claims that pressed buttons
// have a highlight of 0x66999999, but that's clearly wrong. The videos in the
// spec show that buttons have a composited highlight of #E1E1E1 on a background
// of #FAFAFA. Assuming that the highlight really has an opacity of 0x66, we can
// solve for the actual color of the highlight:
const
Color
_kLightThemeHighlightColor
=
const
Color
(
0x66BCBCBC
);
// The same video shows the splash compositing to #D7D7D7 on a background of
// #E1E1E1. Again, assuming the splash has an opacity of 0x66, we can solve for
// the actual color of the splash:
const
Color
_kLightThemeSplashColor
=
const
Color
(
0x66C8C8C8
);
// Unfortunately, a similar video isn't available for the dark theme, which
// means we assume the values in the spec are actually correct.
const
Color
_kDarkThemeHighlightColor
=
const
Color
(
0x40CCCCCC
);
const
Color
_kDarkThemeSplashColor
=
const
Color
(
0x40CCCCCC
);
class
ThemeData
{
ThemeData
({
...
...
@@ -27,7 +44,8 @@ class ThemeData {
// Some users want the pre-multiplied color, others just want the opacity.
hintColor
=
brightness
==
ThemeBrightness
.
dark
?
const
Color
(
0x42FFFFFF
)
:
const
Color
(
0x4C000000
),
hintOpacity
=
brightness
==
ThemeBrightness
.
dark
?
0.26
:
0.30
,
highlightColor
=
brightness
==
ThemeBrightness
.
dark
?
const
Color
(
0x42FFFFFF
)
:
const
Color
(
0x1F000000
),
highlightColor
=
brightness
==
ThemeBrightness
.
dark
?
_kDarkThemeHighlightColor
:
_kLightThemeHighlightColor
,
splashColor
=
brightness
==
ThemeBrightness
.
dark
?
_kDarkThemeSplashColor
:
_kLightThemeSplashColor
,
text
=
brightness
==
ThemeBrightness
.
dark
?
Typography
.
white
:
Typography
.
black
{
assert
(
brightness
!=
null
);
...
...
@@ -70,6 +88,7 @@ class ThemeData {
final
Color
dividerColor
;
final
Color
hintColor
;
final
Color
highlightColor
;
final
Color
splashColor
;
final
double
hintOpacity
;
/// Text with a color that contrasts with the card and canvas colors.
...
...
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