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
328a262e
Unverified
Commit
328a262e
authored
Mar 02, 2021
by
Michael Goderbauer
Committed by
GitHub
Mar 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Toggable Refactor (#76745)" (#77068)
This reverts commit
14552a96
.
parent
9964e8fe
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1307 additions
and
1048 deletions
+1307
-1048
checkbox.dart
packages/flutter/lib/src/material/checkbox.dart
+229
-116
radio.dart
packages/flutter/lib/src/material/radio.dart
+201
-62
switch.dart
packages/flutter/lib/src/material/switch.dart
+416
-304
toggleable.dart
packages/flutter/lib/src/material/toggleable.dart
+356
-430
checkbox_test.dart
packages/flutter/test/material/checkbox_test.dart
+35
-46
radio_test.dart
packages/flutter/test/material/radio_test.dart
+1
-26
switch_list_tile_test.dart
packages/flutter/test/material/switch_list_tile_test.dart
+1
-1
switch_test.dart
packages/flutter/test/material/switch_test.dart
+68
-63
No files found.
packages/flutter/lib/src/material/checkbox.dart
View file @
328a262e
...
@@ -290,39 +290,56 @@ class Checkbox extends StatefulWidget {
...
@@ -290,39 +290,56 @@ class Checkbox extends StatefulWidget {
_CheckboxState
createState
()
=>
_CheckboxState
();
_CheckboxState
createState
()
=>
_CheckboxState
();
}
}
class
_CheckboxState
extends
State
<
Checkbox
>
with
TickerProviderStateMixin
,
ToggleableStateMixin
{
class
_CheckboxState
extends
State
<
Checkbox
>
with
TickerProviderStateMixin
{
final
_CheckboxPainter
_painter
=
_CheckboxPainter
()
;
bool
get
enabled
=>
widget
.
onChanged
!=
null
;
bool
?
_previousValue
;
late
Map
<
Type
,
Action
<
Intent
>>
_actionMap
;
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
_previousValue
=
widget
.
value
;
_actionMap
=
<
Type
,
Action
<
Intent
>>{
ActivateIntent:
CallbackAction
<
ActivateIntent
>(
onInvoke:
_actionHandler
),
};
}
}
@override
void
_actionHandler
(
ActivateIntent
intent
)
{
void
didUpdateWidget
(
Checkbox
oldWidget
)
{
if
(
widget
.
onChanged
!=
null
)
{
super
.
didUpdateWidget
(
oldWidget
);
switch
(
widget
.
value
)
{
if
(
oldWidget
.
value
!=
widget
.
value
)
{
case
false
:
_previousValue
=
oldWidget
.
value
;
widget
.
onChanged
!(
true
);
animateToValue
();
break
;
case
true
:
widget
.
onChanged
!(
widget
.
tristate
?
null
:
false
);
break
;
case
null
:
widget
.
onChanged
!(
false
);
break
;
}
}
}
final
RenderObject
renderObject
=
context
.
findRenderObject
()!;
renderObject
.
sendSemanticsEvent
(
const
TapSemanticEvent
());
}
}
@override
bool
_focused
=
false
;
void
dispose
()
{
void
_handleFocusHighlightChanged
(
bool
focused
)
{
_painter
.
dispose
();
if
(
focused
!=
_focused
)
{
super
.
dispose
();
setState
(()
{
_focused
=
focused
;
});
}
}
}
@override
bool
_hovering
=
false
;
ValueChanged
<
bool
?>?
get
onChanged
=>
widget
.
onChanged
;
void
_handleHoverChanged
(
bool
hovering
)
{
if
(
hovering
!=
_hovering
)
{
@override
setState
(()
{
_hovering
=
hovering
;
});
bool
get
tristate
=>
widget
.
tristate
;
}
}
@override
Set
<
MaterialState
>
get
_states
=>
<
MaterialState
>{
bool
?
get
value
=>
widget
.
value
;
if
(!
enabled
)
MaterialState
.
disabled
,
if
(
_hovering
)
MaterialState
.
hovered
,
if
(
_focused
)
MaterialState
.
focused
,
if
(
widget
.
value
==
null
||
widget
.
value
!)
MaterialState
.
selected
,
};
MaterialStateProperty
<
Color
?>
get
_widgetFillColor
{
MaterialStateProperty
<
Color
?>
get
_widgetFillColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
...
@@ -369,17 +386,14 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
...
@@ -369,17 +386,14 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
break
;
break
;
}
}
size
+=
effectiveVisualDensity
.
baseSizeAdjustment
;
size
+=
effectiveVisualDensity
.
baseSizeAdjustment
;
final
BoxConstraints
additionalConstraints
=
BoxConstraints
.
tight
(
size
);
final
MaterialStateProperty
<
MouseCursor
>
effectiveMouseCursor
=
MaterialStateProperty
.
resolveWith
<
MouseCursor
>((
Set
<
MaterialState
>
states
)
{
final
MouseCursor
effectiveMouseCursor
=
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
_states
)
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
states
)
??
themeData
.
checkboxTheme
.
mouseCursor
?.
resolve
(
_states
)
??
themeData
.
checkboxTheme
.
mouseCursor
?.
resolve
(
states
)
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
_states
);
??
MaterialStateMouseCursor
.
clickable
.
resolve
(
states
);
});
// Colors need to be resolved in selected and non selected states separately
// Colors need to be resolved in selected and non selected states separately
// so that they can be lerped between.
// so that they can be lerped between.
final
Set
<
MaterialState
>
activeStates
=
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
activeStates
=
_
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
states
..
remove
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
_
states
..
remove
(
MaterialState
.
selected
);
final
Color
effectiveActiveColor
=
widget
.
fillColor
?.
resolve
(
activeStates
)
final
Color
effectiveActiveColor
=
widget
.
fillColor
?.
resolve
(
activeStates
)
??
_widgetFillColor
.
resolve
(
activeStates
)
??
_widgetFillColor
.
resolve
(
activeStates
)
??
themeData
.
checkboxTheme
.
fillColor
?.
resolve
(
activeStates
)
??
themeData
.
checkboxTheme
.
fillColor
?.
resolve
(
activeStates
)
...
@@ -389,13 +403,13 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
...
@@ -389,13 +403,13 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
??
themeData
.
checkboxTheme
.
fillColor
?.
resolve
(
inactiveStates
)
??
themeData
.
checkboxTheme
.
fillColor
?.
resolve
(
inactiveStates
)
??
_defaultFillColor
.
resolve
(
inactiveStates
);
??
_defaultFillColor
.
resolve
(
inactiveStates
);
final
Set
<
MaterialState
>
focusedStates
=
states
..
add
(
MaterialState
.
focused
);
final
Set
<
MaterialState
>
focusedStates
=
_
states
..
add
(
MaterialState
.
focused
);
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
??
widget
.
focusColor
??
widget
.
focusColor
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
themeData
.
focusColor
;
??
themeData
.
focusColor
;
final
Set
<
MaterialState
>
hoveredStates
=
states
..
add
(
MaterialState
.
hovered
);
final
Set
<
MaterialState
>
hoveredStates
=
_
states
..
add
(
MaterialState
.
hovered
);
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
??
widget
.
hoverColor
??
widget
.
hoverColor
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
...
@@ -411,96 +425,195 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
...
@@ -411,96 +425,195 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
themeData
.
checkboxTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
effectiveActiveColor
.
withAlpha
(
kRadialReactionAlpha
);
??
effectiveActiveColor
.
withAlpha
(
kRadialReactionAlpha
);
final
Color
effectiveCheckColor
=
widget
.
checkColor
final
Color
effectiveCheckColor
=
widget
.
checkColor
??
themeData
.
checkboxTheme
.
checkColor
?.
resolve
(
states
)
??
themeData
.
checkboxTheme
.
checkColor
?.
resolve
(
_
states
)
??
const
Color
(
0xFFFFFFFF
);
??
const
Color
(
0xFFFFFFFF
);
return
Semantics
(
return
FocusableActionDetector
(
checked:
widget
.
value
==
true
,
actions:
_actionMap
,
child:
buildToggleable
(
focusNode:
widget
.
focusNode
,
mouseCursor:
effectiveMouseCursor
,
autofocus:
widget
.
autofocus
,
focusNode:
widget
.
focusNode
,
enabled:
enabled
,
autofocus:
widget
.
autofocus
,
onShowFocusHighlight:
_handleFocusHighlightChanged
,
size:
size
,
onShowHoverHighlight:
_handleHoverChanged
,
painter:
_painter
mouseCursor:
effectiveMouseCursor
,
..
position
=
position
child:
Builder
(
..
reaction
=
reaction
builder:
(
BuildContext
context
)
{
..
reactionFocusFade
=
reactionFocusFade
return
_CheckboxRenderObjectWidget
(
..
reactionHoverFade
=
reactionHoverFade
value:
widget
.
value
,
..
inactiveReactionColor
=
effectiveInactivePressedOverlayColor
tristate:
widget
.
tristate
,
..
reactionColor
=
effectiveActivePressedOverlayColor
activeColor:
effectiveActiveColor
,
..
hoverColor
=
effectiveHoverOverlayColor
checkColor:
effectiveCheckColor
,
..
focusColor
=
effectiveFocusOverlayColor
inactiveColor:
effectiveInactiveColor
,
..
splashRadius
=
widget
.
splashRadius
??
themeData
.
checkboxTheme
.
splashRadius
??
kRadialReactionRadius
focusColor:
effectiveFocusOverlayColor
,
..
downPosition
=
downPosition
hoverColor:
effectiveHoverOverlayColor
,
..
isFocused
=
states
.
contains
(
MaterialState
.
focused
)
reactionColor:
effectiveActivePressedOverlayColor
,
..
isHovered
=
states
.
contains
(
MaterialState
.
hovered
)
inactiveReactionColor:
effectiveInactivePressedOverlayColor
,
..
activeColor
=
effectiveActiveColor
splashRadius:
widget
.
splashRadius
??
themeData
.
checkboxTheme
.
splashRadius
??
kRadialReactionRadius
,
..
inactiveColor
=
effectiveInactiveColor
onChanged:
widget
.
onChanged
,
..
checkColor
=
effectiveCheckColor
additionalConstraints:
additionalConstraints
,
..
value
=
value
vsync:
this
,
..
previousValue
=
_previousValue
hasFocus:
_focused
,
..
shape
=
widget
.
shape
??
themeData
.
checkboxTheme
.
shape
??
const
RoundedRectangleBorder
(
hovering:
_hovering
,
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
1.0
))
side:
widget
.
side
??
themeData
.
checkboxTheme
.
side
,
)
shape:
widget
.
shape
??
themeData
.
checkboxTheme
.
shape
??
const
RoundedRectangleBorder
(
..
side
=
widget
.
side
??
themeData
.
checkboxTheme
.
side
,
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
1.0
)),
),
);
},
),
),
);
);
}
}
}
}
const
double
_kEdgeSize
=
Checkbox
.
width
;
class
_CheckboxRenderObjectWidget
extends
LeafRenderObjectWidget
{
const
double
_kStrokeWidth
=
2.0
;
const
_CheckboxRenderObjectWidget
({
Key
?
key
,
required
this
.
value
,
required
this
.
tristate
,
required
this
.
activeColor
,
required
this
.
checkColor
,
required
this
.
inactiveColor
,
required
this
.
focusColor
,
required
this
.
hoverColor
,
required
this
.
reactionColor
,
required
this
.
inactiveReactionColor
,
required
this
.
splashRadius
,
required
this
.
onChanged
,
required
this
.
vsync
,
required
this
.
additionalConstraints
,
required
this
.
hasFocus
,
required
this
.
hovering
,
required
this
.
shape
,
required
this
.
side
,
})
:
assert
(
tristate
!=
null
),
assert
(
tristate
||
value
!=
null
),
assert
(
activeColor
!=
null
),
assert
(
inactiveColor
!=
null
),
assert
(
vsync
!=
null
),
super
(
key:
key
);
class
_CheckboxPainter
extends
ToggleablePainter
{
final
bool
?
value
;
Color
get
checkColor
=>
_checkColor
!;
final
bool
tristate
;
Color
?
_checkColor
;
final
bool
hasFocus
;
set
checkColor
(
Color
value
)
{
final
bool
hovering
;
if
(
_checkColor
==
value
)
{
final
Color
activeColor
;
return
;
final
Color
checkColor
;
}
final
Color
inactiveColor
;
_checkColor
=
value
;
final
Color
focusColor
;
notifyListeners
();
final
Color
hoverColor
;
}
final
Color
reactionColor
;
final
Color
inactiveReactionColor
;
final
double
splashRadius
;
final
ValueChanged
<
bool
?>?
onChanged
;
final
TickerProvider
vsync
;
final
BoxConstraints
additionalConstraints
;
final
OutlinedBorder
shape
;
final
BorderSide
?
side
;
bool
?
get
value
=>
_value
;
@override
bool
?
_value
;
_RenderCheckbox
createRenderObject
(
BuildContext
context
)
=>
_RenderCheckbox
(
set
value
(
bool
?
value
)
{
value:
value
,
if
(
_value
==
value
)
{
tristate:
tristate
,
return
;
activeColor:
activeColor
,
}
checkColor:
checkColor
,
_value
=
value
;
inactiveColor:
inactiveColor
,
notifyListeners
();
focusColor:
focusColor
,
}
hoverColor:
hoverColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
onChanged:
onChanged
,
vsync:
vsync
,
additionalConstraints:
additionalConstraints
,
hasFocus:
hasFocus
,
hovering:
hovering
,
shape:
shape
,
side:
side
,
);
bool
?
get
previousValue
=>
_previousValue
;
@override
bool
?
_previousValue
;
void
updateRenderObject
(
BuildContext
context
,
_RenderCheckbox
renderObject
)
{
set
previousValue
(
bool
?
value
)
{
renderObject
if
(
_previousValue
==
value
)
{
// The `tristate` must be changed before `value` due to the assertion at
return
;
// the beginning of `set value`.
}
..
tristate
=
tristate
_previousValue
=
value
;
..
value
=
value
notifyListeners
();
..
activeColor
=
activeColor
..
checkColor
=
checkColor
..
inactiveColor
=
inactiveColor
..
focusColor
=
focusColor
..
hoverColor
=
hoverColor
..
reactionColor
=
reactionColor
..
inactiveReactionColor
=
inactiveReactionColor
..
splashRadius
=
splashRadius
..
onChanged
=
onChanged
..
additionalConstraints
=
additionalConstraints
..
vsync
=
vsync
..
hasFocus
=
hasFocus
..
hovering
=
hovering
..
shape
=
shape
..
side
=
side
;
}
}
}
const
double
_kEdgeSize
=
Checkbox
.
width
;
const
double
_kStrokeWidth
=
2.0
;
class
_RenderCheckbox
extends
RenderToggleable
{
_RenderCheckbox
({
bool
?
value
,
required
bool
tristate
,
required
Color
activeColor
,
required
this
.
checkColor
,
required
Color
inactiveColor
,
Color
?
focusColor
,
Color
?
hoverColor
,
Color
?
reactionColor
,
Color
?
inactiveReactionColor
,
required
double
splashRadius
,
required
BoxConstraints
additionalConstraints
,
ValueChanged
<
bool
?>?
onChanged
,
required
bool
hasFocus
,
required
bool
hovering
,
required
this
.
shape
,
required
this
.
side
,
required
TickerProvider
vsync
,
})
:
_oldValue
=
value
,
super
(
value:
value
,
tristate:
tristate
,
activeColor:
activeColor
,
inactiveColor:
inactiveColor
,
focusColor:
focusColor
,
hoverColor:
hoverColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
onChanged:
onChanged
,
additionalConstraints:
additionalConstraints
,
vsync:
vsync
,
hasFocus:
hasFocus
,
hovering:
hovering
,
);
bool
?
_oldValue
;
Color
checkColor
;
OutlinedBorder
shape
;
BorderSide
?
side
;
OutlinedBorder
get
shape
=>
_shape
!;
@override
OutlinedBorder
?
_shape
;
set
value
(
bool
?
newValue
)
{
set
shape
(
OutlinedBorder
value
)
{
if
(
newValue
==
value
)
if
(
_shape
==
value
)
{
return
;
return
;
}
_oldValue
=
value
;
_shape
=
value
;
super
.
value
=
newValue
;
notifyListeners
();
}
}
BorderSide
?
get
side
=>
_side
;
@override
BorderSide
?
_side
;
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
set
side
(
BorderSide
?
value
)
{
super
.
describeSemanticsConfiguration
(
config
);
if
(
_side
==
value
)
{
config
.
isChecked
=
value
==
true
;
return
;
}
_side
=
value
;
notifyListeners
();
}
}
// The square outer bounds of the checkbox at t, with the specified origin.
// The square outer bounds of the checkbox at t, with the specified origin.
...
@@ -531,11 +644,10 @@ class _CheckboxPainter extends ToggleablePainter {
...
@@ -531,11 +644,10 @@ class _CheckboxPainter extends ToggleablePainter {
void
_drawBorder
(
Canvas
canvas
,
Rect
outer
,
double
t
,
Paint
paint
)
{
void
_drawBorder
(
Canvas
canvas
,
Rect
outer
,
double
t
,
Paint
paint
)
{
assert
(
t
>=
0.0
&&
t
<=
0.5
);
assert
(
t
>=
0.0
&&
t
<=
0.5
);
OutlinedBorder
resolvedShape
=
shape
;
if
(
side
==
null
)
{
if
(
side
==
null
)
{
resolvedShape
=
resolvedS
hape
.
copyWith
(
side:
BorderSide
(
width:
2
,
color:
paint
.
color
));
shape
=
s
hape
.
copyWith
(
side:
BorderSide
(
width:
2
,
color:
paint
.
color
));
}
}
resolvedS
hape
.
copyWith
(
side:
side
).
paint
(
canvas
,
outer
);
s
hape
.
copyWith
(
side:
side
).
paint
(
canvas
,
outer
);
}
}
void
_drawCheck
(
Canvas
canvas
,
Offset
origin
,
double
t
,
Paint
paint
)
{
void
_drawCheck
(
Canvas
canvas
,
Offset
origin
,
double
t
,
Paint
paint
)
{
...
@@ -574,18 +686,19 @@ class _CheckboxPainter extends ToggleablePainter {
...
@@ -574,18 +686,19 @@ class _CheckboxPainter extends ToggleablePainter {
}
}
@override
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
paintRadialReaction
(
canvas:
canvas
,
origin:
size
.
center
(
Offset
.
zero
));
final
Canvas
canvas
=
context
.
canvas
;
paintRadialReaction
(
canvas
,
offset
,
size
.
center
(
Offset
.
zero
));
final
Paint
strokePaint
=
_createStrokePaint
();
final
Paint
strokePaint
=
_createStrokePaint
();
final
Offset
origin
=
size
/
2.0
-
const
Size
.
square
(
_kEdgeSize
)
/
2.0
as
Offset
;
final
Offset
origin
=
offset
+
(
size
/
2.0
-
const
Size
.
square
(
_kEdgeSize
)
/
2.0
as
Offset
)
;
final
AnimationStatus
status
=
position
.
status
;
final
AnimationStatus
status
=
position
.
status
;
final
double
tNormalized
=
status
==
AnimationStatus
.
forward
||
status
==
AnimationStatus
.
completed
final
double
tNormalized
=
status
==
AnimationStatus
.
forward
||
status
==
AnimationStatus
.
completed
?
position
.
value
?
position
.
value
:
1.0
-
position
.
value
;
:
1.0
-
position
.
value
;
// Four cases: false to null, false to true, null to false, true to false
// Four cases: false to null, false to true, null to false, true to false
if
(
previous
Value
==
false
||
value
==
false
)
{
if
(
_old
Value
==
false
||
value
==
false
)
{
final
double
t
=
value
==
false
?
1.0
-
tNormalized
:
tNormalized
;
final
double
t
=
value
==
false
?
1.0
-
tNormalized
:
tNormalized
;
final
Rect
outer
=
_outerRectAt
(
origin
,
t
);
final
Rect
outer
=
_outerRectAt
(
origin
,
t
);
final
Path
emptyCheckboxPath
=
shape
.
copyWith
(
side:
side
).
getOuterPath
(
outer
);
final
Path
emptyCheckboxPath
=
shape
.
copyWith
(
side:
side
).
getOuterPath
(
outer
);
...
@@ -597,7 +710,7 @@ class _CheckboxPainter extends ToggleablePainter {
...
@@ -597,7 +710,7 @@ class _CheckboxPainter extends ToggleablePainter {
canvas
.
drawPath
(
emptyCheckboxPath
,
paint
);
canvas
.
drawPath
(
emptyCheckboxPath
,
paint
);
final
double
tShrink
=
(
t
-
0.5
)
*
2.0
;
final
double
tShrink
=
(
t
-
0.5
)
*
2.0
;
if
(
previous
Value
==
null
||
value
==
null
)
if
(
_old
Value
==
null
||
value
==
null
)
_drawDash
(
canvas
,
origin
,
tShrink
,
strokePaint
);
_drawDash
(
canvas
,
origin
,
tShrink
,
strokePaint
);
else
else
_drawCheck
(
canvas
,
origin
,
tShrink
,
strokePaint
);
_drawCheck
(
canvas
,
origin
,
tShrink
,
strokePaint
);
...
@@ -609,7 +722,7 @@ class _CheckboxPainter extends ToggleablePainter {
...
@@ -609,7 +722,7 @@ class _CheckboxPainter extends ToggleablePainter {
if
(
tNormalized
<=
0.5
)
{
if
(
tNormalized
<=
0.5
)
{
final
double
tShrink
=
1.0
-
tNormalized
*
2.0
;
final
double
tShrink
=
1.0
-
tNormalized
*
2.0
;
if
(
previous
Value
==
true
)
if
(
_old
Value
==
true
)
_drawCheck
(
canvas
,
origin
,
tShrink
,
strokePaint
);
_drawCheck
(
canvas
,
origin
,
tShrink
,
strokePaint
);
else
else
_drawDash
(
canvas
,
origin
,
tShrink
,
strokePaint
);
_drawDash
(
canvas
,
origin
,
tShrink
,
strokePaint
);
...
...
packages/flutter/lib/src/material/radio.dart
View file @
328a262e
...
@@ -353,47 +353,64 @@ class Radio<T> extends StatefulWidget {
...
@@ -353,47 +353,64 @@ class Radio<T> extends StatefulWidget {
/// {@macro flutter.widgets.Focus.autofocus}
/// {@macro flutter.widgets.Focus.autofocus}
final
bool
autofocus
;
final
bool
autofocus
;
bool
get
_selected
=>
value
==
groupValue
;
@override
@override
_RadioState
<
T
>
createState
()
=>
_RadioState
<
T
>();
_RadioState
<
T
>
createState
()
=>
_RadioState
<
T
>();
}
}
class
_RadioState
<
T
>
extends
State
<
Radio
<
T
>>
with
TickerProviderStateMixin
,
ToggleableStateMixin
{
class
_RadioState
<
T
>
extends
State
<
Radio
<
T
>>
with
TickerProviderStateMixin
{
final
_RadioPainter
_painter
=
_RadioPainter
();
bool
get
enabled
=>
widget
.
onChanged
!=
null
;
late
Map
<
Type
,
Action
<
Intent
>>
_actionMap
;
void
_handleChanged
(
bool
?
selected
)
{
@override
if
(
selected
==
null
)
{
void
initState
()
{
widget
.
onChanged
!(
null
);
super
.
initState
();
return
;
_actionMap
=
<
Type
,
Action
<
Intent
>>{
}
ActivateIntent:
CallbackAction
<
ActivateIntent
>(
if
(
selected
)
{
onInvoke:
_actionHandler
,
),
};
}
void
_actionHandler
(
ActivateIntent
intent
)
{
if
(
widget
.
onChanged
!=
null
)
{
widget
.
onChanged
!(
widget
.
value
);
widget
.
onChanged
!(
widget
.
value
);
}
}
final
RenderObject
renderObject
=
context
.
findRenderObject
()!;
renderObject
.
sendSemanticsEvent
(
const
TapSemanticEvent
());
}
}
@override
bool
_focused
=
false
;
void
didUpdateWidget
(
Radio
<
T
>
oldWidget
)
{
void
_handleHighlightChanged
(
bool
focused
)
{
super
.
didUpdateWidget
(
oldWidget
);
if
(
_focused
!=
focused
)
{
if
(
widget
.
_selected
!=
oldWidget
.
_selected
)
{
setState
(()
{
_focused
=
focused
;
});
animateToValue
();
}
}
}
}
@override
bool
_hovering
=
false
;
void
dispose
()
{
void
_handleHoverChanged
(
bool
hovering
)
{
_painter
.
dispose
();
if
(
_hovering
!=
hovering
)
{
super
.
dispose
();
setState
(()
{
_hovering
=
hovering
;
});
}
}
}
@override
void
_handleChanged
(
bool
?
selected
)
{
ValueChanged
<
bool
?>?
get
onChanged
=>
widget
.
onChanged
!=
null
?
_handleChanged
:
null
;
if
(
selected
==
null
)
{
widget
.
onChanged
!(
null
);
return
;
}
if
(
selected
)
{
widget
.
onChanged
!(
widget
.
value
);
}
}
@override
bool
get
_selected
=>
widget
.
value
==
widget
.
groupValue
;
bool
get
tristate
=>
widget
.
toggleable
;
@override
Set
<
MaterialState
>
get
_states
=>
<
MaterialState
>{
bool
?
get
value
=>
widget
.
_selected
;
if
(!
enabled
)
MaterialState
.
disabled
,
if
(
_hovering
)
MaterialState
.
hovered
,
if
(
_focused
)
MaterialState
.
focused
,
if
(
_selected
)
MaterialState
.
selected
,
};
MaterialStateProperty
<
Color
?>
get
_widgetFillColor
{
MaterialStateProperty
<
Color
?>
get
_widgetFillColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
...
@@ -440,17 +457,15 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
...
@@ -440,17 +457,15 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
break
;
break
;
}
}
size
+=
effectiveVisualDensity
.
baseSizeAdjustment
;
size
+=
effectiveVisualDensity
.
baseSizeAdjustment
;
final
BoxConstraints
additionalConstraints
=
BoxConstraints
.
tight
(
size
);
final
MaterialStateProperty
<
MouseCursor
>
effectiveMouseCursor
=
MaterialStateProperty
.
resolveWith
<
MouseCursor
>((
Set
<
MaterialState
>
states
)
{
final
MouseCursor
effectiveMouseCursor
=
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
_states
)
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
states
)
??
themeData
.
radioTheme
.
mouseCursor
?.
resolve
(
_states
)
??
themeData
.
radioTheme
.
mouseCursor
?.
resolve
(
states
)
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
_states
);
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
states
);
});
// Colors need to be resolved in selected and non selected states separately
// Colors need to be resolved in selected and non selected states separately
// so that they can be lerped between.
// so that they can be lerped between.
final
Set
<
MaterialState
>
activeStates
=
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
activeStates
=
_
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
states
..
remove
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
_
states
..
remove
(
MaterialState
.
selected
);
final
Color
effectiveActiveColor
=
widget
.
fillColor
?.
resolve
(
activeStates
)
final
Color
effectiveActiveColor
=
widget
.
fillColor
?.
resolve
(
activeStates
)
??
_widgetFillColor
.
resolve
(
activeStates
)
??
_widgetFillColor
.
resolve
(
activeStates
)
??
themeData
.
radioTheme
.
fillColor
?.
resolve
(
activeStates
)
??
themeData
.
radioTheme
.
fillColor
?.
resolve
(
activeStates
)
...
@@ -460,13 +475,13 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
...
@@ -460,13 +475,13 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
??
themeData
.
radioTheme
.
fillColor
?.
resolve
(
inactiveStates
)
??
themeData
.
radioTheme
.
fillColor
?.
resolve
(
inactiveStates
)
??
_defaultFillColor
.
resolve
(
inactiveStates
);
??
_defaultFillColor
.
resolve
(
inactiveStates
);
final
Set
<
MaterialState
>
focusedStates
=
states
..
add
(
MaterialState
.
focused
);
final
Set
<
MaterialState
>
focusedStates
=
_
states
..
add
(
MaterialState
.
focused
);
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
??
widget
.
focusColor
??
widget
.
focusColor
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
themeData
.
focusColor
;
??
themeData
.
focusColor
;
final
Set
<
MaterialState
>
hoveredStates
=
states
..
add
(
MaterialState
.
hovered
);
final
Set
<
MaterialState
>
hoveredStates
=
_
states
..
add
(
MaterialState
.
hovered
);
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
??
widget
.
hoverColor
??
widget
.
hoverColor
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
...
@@ -482,40 +497,156 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
...
@@ -482,40 +497,156 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
themeData
.
radioTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
effectiveActiveColor
.
withAlpha
(
kRadialReactionAlpha
);
??
effectiveActiveColor
.
withAlpha
(
kRadialReactionAlpha
);
return
Semantics
(
inMutuallyExclusiveGroup:
true
,
return
FocusableActionDetector
(
checked:
widget
.
_selected
,
actions:
_actionMap
,
child:
buildToggleable
(
focusNode:
widget
.
focusNode
,
focusNode:
widget
.
focusNode
,
autofocus:
widget
.
autofocus
,
autofocus:
widget
.
autofocus
,
mouseCursor:
effectiveMouseCursor
,
mouseCursor:
effectiveMouseCursor
,
enabled:
enabled
,
size:
size
,
onShowFocusHighlight:
_handleHighlightChanged
,
painter:
_painter
onShowHoverHighlight:
_handleHoverChanged
,
..
position
=
position
child:
Builder
(
..
reaction
=
reaction
builder:
(
BuildContext
context
)
{
..
reactionFocusFade
=
reactionFocusFade
return
_RadioRenderObjectWidget
(
..
reactionHoverFade
=
reactionHoverFade
selected:
_selected
,
..
inactiveReactionColor
=
effectiveInactivePressedOverlayColor
activeColor:
effectiveActiveColor
,
..
reactionColor
=
effectiveActivePressedOverlayColor
inactiveColor:
effectiveInactiveColor
,
..
hoverColor
=
effectiveHoverOverlayColor
focusColor:
effectiveFocusOverlayColor
,
..
focusColor
=
effectiveFocusOverlayColor
hoverColor:
effectiveHoverOverlayColor
,
..
splashRadius
=
widget
.
splashRadius
??
themeData
.
radioTheme
.
splashRadius
??
kRadialReactionRadius
reactionColor:
effectiveActivePressedOverlayColor
,
..
downPosition
=
downPosition
inactiveReactionColor:
effectiveInactivePressedOverlayColor
,
..
isFocused
=
states
.
contains
(
MaterialState
.
focused
)
splashRadius:
widget
.
splashRadius
??
themeData
.
radioTheme
.
splashRadius
??
kRadialReactionRadius
,
..
isHovered
=
states
.
contains
(
MaterialState
.
hovered
)
onChanged:
enabled
?
_handleChanged
:
null
,
..
activeColor
=
effectiveActiveColor
toggleable:
widget
.
toggleable
,
..
inactiveColor
=
effectiveInactiveColor
additionalConstraints:
additionalConstraints
,
vsync:
this
,
hasFocus:
_focused
,
hovering:
_hovering
,
);
},
),
),
);
);
}
}
}
}
class
_RadioPainter
extends
ToggleablePainter
{
class
_RadioRenderObjectWidget
extends
LeafRenderObjectWidget
{
const
_RadioRenderObjectWidget
({
Key
?
key
,
required
this
.
selected
,
required
this
.
activeColor
,
required
this
.
inactiveColor
,
required
this
.
focusColor
,
required
this
.
hoverColor
,
required
this
.
reactionColor
,
required
this
.
inactiveReactionColor
,
required
this
.
additionalConstraints
,
this
.
onChanged
,
required
this
.
toggleable
,
required
this
.
vsync
,
required
this
.
hasFocus
,
required
this
.
hovering
,
required
this
.
splashRadius
,
})
:
assert
(
selected
!=
null
),
assert
(
activeColor
!=
null
),
assert
(
inactiveColor
!=
null
),
assert
(
vsync
!=
null
),
assert
(
toggleable
!=
null
),
super
(
key:
key
);
final
bool
selected
;
final
bool
hasFocus
;
final
bool
hovering
;
final
Color
inactiveColor
;
final
Color
activeColor
;
final
Color
focusColor
;
final
Color
hoverColor
;
final
Color
reactionColor
;
final
Color
inactiveReactionColor
;
final
double
splashRadius
;
final
ValueChanged
<
bool
?>?
onChanged
;
final
bool
toggleable
;
final
TickerProvider
vsync
;
final
BoxConstraints
additionalConstraints
;
@override
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
_RenderRadio
createRenderObject
(
BuildContext
context
)
=>
_RenderRadio
(
paintRadialReaction
(
canvas:
canvas
,
origin:
size
.
center
(
Offset
.
zero
));
value:
selected
,
activeColor:
activeColor
,
inactiveColor:
inactiveColor
,
focusColor:
focusColor
,
hoverColor:
hoverColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
onChanged:
onChanged
,
tristate:
toggleable
,
vsync:
vsync
,
additionalConstraints:
additionalConstraints
,
hasFocus:
hasFocus
,
hovering:
hovering
,
);
final
Offset
center
=
(
Offset
.
zero
&
size
).
center
;
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderRadio
renderObject
)
{
renderObject
..
value
=
selected
..
activeColor
=
activeColor
..
inactiveColor
=
inactiveColor
..
focusColor
=
focusColor
..
hoverColor
=
hoverColor
..
reactionColor
=
reactionColor
..
inactiveReactionColor
=
inactiveReactionColor
..
splashRadius
=
splashRadius
..
onChanged
=
onChanged
..
tristate
=
toggleable
..
additionalConstraints
=
additionalConstraints
..
vsync
=
vsync
..
hasFocus
=
hasFocus
..
hovering
=
hovering
;
}
}
class
_RenderRadio
extends
RenderToggleable
{
_RenderRadio
({
required
bool
value
,
required
Color
activeColor
,
required
Color
inactiveColor
,
required
Color
focusColor
,
required
Color
hoverColor
,
required
Color
reactionColor
,
required
Color
inactiveReactionColor
,
required
double
splashRadius
,
required
ValueChanged
<
bool
?>?
onChanged
,
required
bool
tristate
,
required
BoxConstraints
additionalConstraints
,
required
TickerProvider
vsync
,
required
bool
hasFocus
,
required
bool
hovering
,
})
:
super
(
value:
value
,
activeColor:
activeColor
,
inactiveColor:
inactiveColor
,
focusColor:
focusColor
,
hoverColor:
hoverColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
onChanged:
onChanged
,
tristate:
tristate
,
additionalConstraints:
additionalConstraints
,
vsync:
vsync
,
hasFocus:
hasFocus
,
hovering:
hovering
,
);
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
final
Canvas
canvas
=
context
.
canvas
;
paintRadialReaction
(
canvas
,
offset
,
size
.
center
(
Offset
.
zero
));
final
Offset
center
=
(
offset
&
size
).
center
;
// Outer circle
// Outer circle
final
Paint
paint
=
Paint
()
final
Paint
paint
=
Paint
()
...
@@ -530,4 +661,12 @@ class _RadioPainter extends ToggleablePainter {
...
@@ -530,4 +661,12 @@ class _RadioPainter extends ToggleablePainter {
canvas
.
drawCircle
(
center
,
_kInnerRadius
*
position
.
value
,
paint
);
canvas
.
drawCircle
(
center
,
_kInnerRadius
*
position
.
value
,
paint
);
}
}
}
}
@override
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
super
.
describeSemanticsConfiguration
(
config
);
config
..
isInMutuallyExclusiveGroup
=
true
..
isChecked
=
value
==
true
;
}
}
}
packages/flutter/lib/src/material/switch.dart
View file @
328a262e
...
@@ -51,7 +51,7 @@ enum _SwitchType { material, adaptive }
...
@@ -51,7 +51,7 @@ enum _SwitchType { material, adaptive }
/// * [Radio], for selecting among a set of explicit values.
/// * [Radio], for selecting among a set of explicit values.
/// * [Slider], for selecting a value in a range.
/// * [Slider], for selecting a value in a range.
/// * <https://material.io/design/components/selection-controls.html#switches>
/// * <https://material.io/design/components/selection-controls.html#switches>
class
Switch
extends
State
less
Widget
{
class
Switch
extends
State
ful
Widget
{
/// Creates a material design switch.
/// Creates a material design switch.
///
///
/// The switch itself does not maintain any state. Instead, when the state of
/// The switch itself does not maintain any state. Instead, when the state of
...
@@ -359,87 +359,8 @@ class Switch extends StatelessWidget {
...
@@ -359,87 +359,8 @@ class Switch extends StatelessWidget {
/// {@macro flutter.widgets.Focus.autofocus}
/// {@macro flutter.widgets.Focus.autofocus}
final
bool
autofocus
;
final
bool
autofocus
;
Size
_getSwitchSize
(
ThemeData
theme
)
{
final
MaterialTapTargetSize
effectiveMaterialTapTargetSize
=
materialTapTargetSize
??
theme
.
switchTheme
.
materialTapTargetSize
??
theme
.
materialTapTargetSize
;
switch
(
effectiveMaterialTapTargetSize
)
{
case
MaterialTapTargetSize
.
padded
:
return
const
Size
(
_kSwitchWidth
,
_kSwitchHeight
);
case
MaterialTapTargetSize
.
shrinkWrap
:
return
const
Size
(
_kSwitchWidth
,
_kSwitchHeightCollapsed
);
}
}
Widget
_buildCupertinoSwitch
(
BuildContext
context
)
{
final
Size
size
=
_getSwitchSize
(
Theme
.
of
(
context
));
return
Focus
(
focusNode:
focusNode
,
autofocus:
autofocus
,
child:
Container
(
width:
size
.
width
,
// Same size as the Material switch.
height:
size
.
height
,
alignment:
Alignment
.
center
,
child:
CupertinoSwitch
(
dragStartBehavior:
dragStartBehavior
,
value:
value
,
onChanged:
onChanged
,
activeColor:
activeColor
,
trackColor:
inactiveTrackColor
),
),
);
}
Widget
_buildMaterialSwitch
(
BuildContext
context
)
{
return
_MaterialSwitch
(
value:
value
,
onChanged:
onChanged
,
size:
_getSwitchSize
(
Theme
.
of
(
context
)),
activeColor:
activeColor
,
activeTrackColor:
activeTrackColor
,
inactiveThumbColor:
inactiveThumbColor
,
inactiveTrackColor:
inactiveTrackColor
,
activeThumbImage:
activeThumbImage
,
onActiveThumbImageError:
onActiveThumbImageError
,
inactiveThumbImage:
inactiveThumbImage
,
onInactiveThumbImageError:
onInactiveThumbImageError
,
thumbColor:
thumbColor
,
trackColor:
trackColor
,
materialTapTargetSize:
materialTapTargetSize
,
dragStartBehavior:
dragStartBehavior
,
mouseCursor:
mouseCursor
,
focusColor:
focusColor
,
hoverColor:
hoverColor
,
overlayColor:
overlayColor
,
splashRadius:
splashRadius
,
focusNode:
focusNode
,
autofocus:
autofocus
,
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
_SwitchState
createState
()
=>
_SwitchState
();
switch
(
_switchType
)
{
case
_SwitchType
.
material
:
return
_buildMaterialSwitch
(
context
);
case
_SwitchType
.
adaptive
:
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
assert
(
theme
.
platform
!=
null
);
switch
(
theme
.
platform
)
{
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
windows
:
return
_buildMaterialSwitch
(
context
);
case
TargetPlatform
.
iOS
:
case
TargetPlatform
.
macOS
:
return
_buildCupertinoSwitch
(
context
);
}
}
}
}
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
...
@@ -449,95 +370,65 @@ class Switch extends StatelessWidget {
...
@@ -449,95 +370,65 @@ class Switch extends StatelessWidget {
}
}
}
}
class
_MaterialSwitch
extends
StatefulWidget
{
class
_SwitchState
extends
State
<
Switch
>
with
TickerProviderStateMixin
{
const
_MaterialSwitch
({
late
Map
<
Type
,
Action
<
Intent
>>
_actionMap
;
Key
?
key
,
required
this
.
value
,
required
this
.
onChanged
,
required
this
.
size
,
this
.
activeColor
,
this
.
activeTrackColor
,
this
.
inactiveThumbColor
,
this
.
inactiveTrackColor
,
this
.
activeThumbImage
,
this
.
onActiveThumbImageError
,
this
.
inactiveThumbImage
,
this
.
onInactiveThumbImageError
,
this
.
thumbColor
,
this
.
trackColor
,
this
.
materialTapTargetSize
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
mouseCursor
,
this
.
focusColor
,
this
.
hoverColor
,
this
.
overlayColor
,
this
.
splashRadius
,
this
.
focusNode
,
this
.
autofocus
=
false
,
})
:
assert
(
dragStartBehavior
!=
null
),
assert
(
activeThumbImage
!=
null
||
onActiveThumbImageError
==
null
),
assert
(
inactiveThumbImage
!=
null
||
onInactiveThumbImageError
==
null
),
super
(
key:
key
);
final
bool
value
;
final
ValueChanged
<
bool
>?
onChanged
;
final
Color
?
activeColor
;
final
Color
?
activeTrackColor
;
final
Color
?
inactiveThumbColor
;
final
Color
?
inactiveTrackColor
;
final
ImageProvider
?
activeThumbImage
;
final
ImageErrorListener
?
onActiveThumbImageError
;
final
ImageProvider
?
inactiveThumbImage
;
final
ImageErrorListener
?
onInactiveThumbImageError
;
final
MaterialStateProperty
<
Color
?>?
thumbColor
;
final
MaterialStateProperty
<
Color
?>?
trackColor
;
final
MaterialTapTargetSize
?
materialTapTargetSize
;
final
DragStartBehavior
dragStartBehavior
;
final
MouseCursor
?
mouseCursor
;
final
Color
?
focusColor
;
final
Color
?
hoverColor
;
final
MaterialStateProperty
<
Color
?>?
overlayColor
;
final
double
?
splashRadius
;
final
FocusNode
?
focusNode
;
final
bool
autofocus
;
final
Size
size
;
@override
@override
State
<
StatefulWidget
>
createState
()
=>
_MaterialSwitchState
();
void
initState
()
{
}
super
.
initState
();
_actionMap
=
<
Type
,
Action
<
Intent
>>{
ActivateIntent:
CallbackAction
<
ActivateIntent
>(
onInvoke:
_actionHandler
),
};
}
void
_actionHandler
(
ActivateIntent
intent
)
{
if
(
widget
.
onChanged
!=
null
)
{
widget
.
onChanged
!(!
widget
.
value
);
}
final
RenderObject
renderObject
=
context
.
findRenderObject
()!;
renderObject
.
sendSemanticsEvent
(
const
TapSemanticEvent
());
}
class
_MaterialSwitchState
extends
State
<
_MaterialSwitch
>
with
TickerProviderStateMixin
,
ToggleableStateMixin
{
bool
_focused
=
false
;
final
_SwitchPainter
_painter
=
_SwitchPainter
();
void
_handleFocusHighlightChanged
(
bool
focused
)
{
if
(
focused
!=
_focused
)
{
setState
(()
{
_focused
=
focused
;
});
}
}
@override
bool
_hovering
=
false
;
void
didUpdateWidget
(
_MaterialSwitch
oldWidget
)
{
void
_handleHoverChanged
(
bool
hovering
)
{
super
.
didUpdateWidget
(
oldWidget
);
if
(
hovering
!=
_hovering
)
{
if
(
oldWidget
.
value
!=
widget
.
value
)
{
setState
(()
{
_hovering
=
hovering
;
});
// During a drag we may have modified the curve, reset it if its possible
// to do without visual discontinuation.
if
(
position
.
value
==
0.0
||
position
.
value
==
1.0
)
{
position
..
curve
=
Curves
.
easeIn
..
reverseCurve
=
Curves
.
easeOut
;
}
animateToValue
();
}
}
}
}
@override
Size
getSwitchSize
(
ThemeData
theme
)
{
void
dispose
()
{
final
MaterialTapTargetSize
effectiveMaterialTapTargetSize
=
widget
.
materialTapTargetSize
_painter
.
dispose
();
??
theme
.
switchTheme
.
materialTapTargetSize
super
.
dispose
();
??
theme
.
materialTapTargetSize
;
switch
(
effectiveMaterialTapTargetSize
)
{
case
MaterialTapTargetSize
.
padded
:
return
const
Size
(
_kSwitchWidth
,
_kSwitchHeight
);
case
MaterialTapTargetSize
.
shrinkWrap
:
return
const
Size
(
_kSwitchWidth
,
_kSwitchHeightCollapsed
);
}
}
}
@override
bool
get
enabled
=>
widget
.
onChanged
!=
null
;
ValueChanged
<
bool
?>?
get
onChanged
=>
widget
.
onChanged
!=
null
?
_handleChanged
:
null
;
@override
void
_didFinishDragging
()
{
bool
get
tristate
=>
false
;
// The user has finished dragging the thumb of this switch. Rebuild the switch
// to update the animation.
setState
(()
{});
}
@override
Set
<
MaterialState
>
get
_states
=>
<
MaterialState
>{
bool
?
get
value
=>
widget
.
value
;
if
(!
enabled
)
MaterialState
.
disabled
,
if
(
_hovering
)
MaterialState
.
hovered
,
if
(
_focused
)
MaterialState
.
focused
,
if
(
widget
.
value
)
MaterialState
.
selected
,
};
MaterialStateProperty
<
Color
?>
get
_widgetThumbColor
{
MaterialStateProperty
<
Color
?>
get
_widgetThumbColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
...
@@ -596,68 +487,14 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -596,68 +487,14 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
});
});
}
}
double
get
_trackInnerLength
=>
widget
.
size
.
width
-
_kSwitchMinSize
;
Widget
buildMaterialSwitch
(
BuildContext
context
)
{
void
_handleDragStart
(
DragStartDetails
details
)
{
if
(
isInteractive
)
reactionController
.
forward
();
}
void
_handleDragUpdate
(
DragUpdateDetails
details
)
{
if
(
isInteractive
)
{
position
..
curve
=
Curves
.
linear
..
reverseCurve
=
null
;
final
double
delta
=
details
.
primaryDelta
!
/
_trackInnerLength
;
switch
(
Directionality
.
of
(
context
))
{
case
TextDirection
.
rtl
:
positionController
.
value
-=
delta
;
break
;
case
TextDirection
.
ltr
:
positionController
.
value
+=
delta
;
break
;
}
}
}
bool
_needsPositionAnimation
=
false
;
void
_handleDragEnd
(
DragEndDetails
details
)
{
if
(
position
.
value
>=
0.5
!=
widget
.
value
)
{
widget
.
onChanged
!(!
widget
.
value
);
// Wait with finishing the animation until widget.value has changed to
// !widget.value as part of the widget.onChanged call above.
setState
(()
{
_needsPositionAnimation
=
true
;
});
}
else
{
animateToValue
();
}
reactionController
.
reverse
();
}
void
_handleChanged
(
bool
?
value
)
{
assert
(
value
!=
null
);
assert
(
widget
.
onChanged
!=
null
);
widget
.
onChanged
!(
value
!);
}
@override
Widget
build
(
BuildContext
context
)
{
assert
(
debugCheckHasMaterial
(
context
));
assert
(
debugCheckHasMaterial
(
context
));
if
(
_needsPositionAnimation
)
{
_needsPositionAnimation
=
false
;
animateToValue
();
}
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
// Colors need to be resolved in selected and non selected states separately
// Colors need to be resolved in selected and non selected states separately
// so that they can be lerped between.
// so that they can be lerped between.
final
Set
<
MaterialState
>
activeStates
=
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
activeStates
=
_
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
states
..
remove
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
_
states
..
remove
(
MaterialState
.
selected
);
final
Color
effectiveActiveThumbColor
=
widget
.
thumbColor
?.
resolve
(
activeStates
)
final
Color
effectiveActiveThumbColor
=
widget
.
thumbColor
?.
resolve
(
activeStates
)
??
_widgetThumbColor
.
resolve
(
activeStates
)
??
_widgetThumbColor
.
resolve
(
activeStates
)
??
theme
.
switchTheme
.
thumbColor
?.
resolve
(
activeStates
)
??
theme
.
switchTheme
.
thumbColor
?.
resolve
(
activeStates
)
...
@@ -675,13 +512,14 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -675,13 +512,14 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
??
theme
.
switchTheme
.
trackColor
?.
resolve
(
inactiveStates
)
??
theme
.
switchTheme
.
trackColor
?.
resolve
(
inactiveStates
)
??
_defaultTrackColor
.
resolve
(
inactiveStates
);
??
_defaultTrackColor
.
resolve
(
inactiveStates
);
final
Set
<
MaterialState
>
focusedStates
=
states
..
add
(
MaterialState
.
focused
);
final
Set
<
MaterialState
>
focusedStates
=
_states
..
add
(
MaterialState
.
focused
);
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
??
widget
.
focusColor
??
widget
.
focusColor
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
theme
.
focusColor
;
??
theme
.
focusColor
;
final
Set
<
MaterialState
>
hoveredStates
=
states
..
add
(
MaterialState
.
hovered
);
final
Set
<
MaterialState
>
hoveredStates
=
_
states
..
add
(
MaterialState
.
hovered
);
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
??
widget
.
hoverColor
??
widget
.
hoverColor
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
...
@@ -697,65 +535,277 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -697,65 +535,277 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
theme
.
switchTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
effectiveActiveThumbColor
.
withAlpha
(
kRadialReactionAlpha
);
??
effectiveActiveThumbColor
.
withAlpha
(
kRadialReactionAlpha
);
final
MaterialStateProperty
<
MouseCursor
>
effectiveMouseCursor
=
MaterialStateProperty
.
resolveWith
<
MouseCursor
>((
Set
<
MaterialState
>
states
)
{
final
MouseCursor
effectiveMouseCursor
=
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
_states
)
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
states
)
??
theme
.
switchTheme
.
mouseCursor
?.
resolve
(
_states
)
??
theme
.
switchTheme
.
mouseCursor
?.
resolve
(
states
)
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
_states
);
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
states
);
});
return
FocusableActionDetector
(
actions:
_actionMap
,
focusNode:
widget
.
focusNode
,
autofocus:
widget
.
autofocus
,
enabled:
enabled
,
onShowFocusHighlight:
_handleFocusHighlightChanged
,
onShowHoverHighlight:
_handleHoverChanged
,
mouseCursor:
effectiveMouseCursor
,
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
_SwitchRenderObjectWidget
(
dragStartBehavior:
widget
.
dragStartBehavior
,
value:
widget
.
value
,
activeColor:
effectiveActiveThumbColor
,
inactiveColor:
effectiveInactiveThumbColor
,
surfaceColor:
theme
.
colorScheme
.
surface
,
focusColor:
effectiveFocusOverlayColor
,
hoverColor:
effectiveHoverOverlayColor
,
reactionColor:
effectiveActivePressedOverlayColor
,
inactiveReactionColor:
effectiveInactivePressedOverlayColor
,
splashRadius:
widget
.
splashRadius
??
theme
.
switchTheme
.
splashRadius
??
kRadialReactionRadius
,
activeThumbImage:
widget
.
activeThumbImage
,
onActiveThumbImageError:
widget
.
onActiveThumbImageError
,
inactiveThumbImage:
widget
.
inactiveThumbImage
,
onInactiveThumbImageError:
widget
.
onInactiveThumbImageError
,
activeTrackColor:
effectiveActiveTrackColor
,
inactiveTrackColor:
effectiveInactiveTrackColor
,
configuration:
createLocalImageConfiguration
(
context
),
onChanged:
widget
.
onChanged
,
additionalConstraints:
BoxConstraints
.
tight
(
getSwitchSize
(
theme
)),
hasFocus:
_focused
,
hovering:
_hovering
,
state:
this
,
);
},
),
);
}
return
Semantics
(
Widget
buildCupertinoSwitch
(
BuildContext
context
)
{
toggled:
widget
.
value
,
final
Size
size
=
getSwitchSize
(
Theme
.
of
(
context
));
child:
GestureDetector
(
return
Focus
(
excludeFromSemantics:
true
,
focusNode:
widget
.
focusNode
,
onHorizontalDragStart:
_handleDragStart
,
autofocus:
widget
.
autofocus
,
onHorizontalDragUpdate:
_handleDragUpdate
,
child:
Container
(
onHorizontalDragEnd:
_handleDragEnd
,
width:
size
.
width
,
// Same size as the Material switch.
dragStartBehavior:
widget
.
dragStartBehavior
,
height:
size
.
height
,
child:
buildToggleable
(
alignment:
Alignment
.
center
,
mouseCursor:
effectiveMouseCursor
,
child:
CupertinoSwitch
(
focusNode:
widget
.
focusNode
,
dragStartBehavior:
widget
.
dragStartBehavior
,
autofocus:
widget
.
autofocus
,
value:
widget
.
value
,
size:
widget
.
size
,
onChanged:
widget
.
onChanged
,
painter:
_painter
activeColor:
widget
.
activeColor
,
..
position
=
position
trackColor:
widget
.
inactiveTrackColor
..
reaction
=
reaction
..
reactionFocusFade
=
reactionFocusFade
..
reactionHoverFade
=
reactionHoverFade
..
inactiveReactionColor
=
effectiveInactivePressedOverlayColor
..
reactionColor
=
effectiveActivePressedOverlayColor
..
hoverColor
=
effectiveHoverOverlayColor
..
focusColor
=
effectiveFocusOverlayColor
..
splashRadius
=
widget
.
splashRadius
??
theme
.
switchTheme
.
splashRadius
??
kRadialReactionRadius
..
downPosition
=
downPosition
..
isFocused
=
states
.
contains
(
MaterialState
.
focused
)
..
isHovered
=
states
.
contains
(
MaterialState
.
hovered
)
..
activeColor
=
effectiveActiveThumbColor
..
inactiveColor
=
effectiveInactiveThumbColor
..
activeThumbImage
=
widget
.
activeThumbImage
..
onActiveThumbImageError
=
widget
.
onActiveThumbImageError
..
inactiveThumbImage
=
widget
.
inactiveThumbImage
..
onInactiveThumbImageError
=
widget
.
onInactiveThumbImageError
..
activeTrackColor
=
effectiveActiveTrackColor
..
inactiveTrackColor
=
effectiveInactiveTrackColor
..
configuration
=
createLocalImageConfiguration
(
context
)
..
isInteractive
=
isInteractive
..
trackInnerLength
=
_trackInnerLength
..
textDirection
=
Directionality
.
of
(
context
)
..
surfaceColor
=
theme
.
colorScheme
.
surface
),
),
),
),
);
);
}
}
@override
Widget
build
(
BuildContext
context
)
{
switch
(
widget
.
_switchType
)
{
case
_SwitchType
.
material
:
return
buildMaterialSwitch
(
context
);
case
_SwitchType
.
adaptive
:
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
assert
(
theme
.
platform
!=
null
);
switch
(
theme
.
platform
)
{
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
windows
:
return
buildMaterialSwitch
(
context
);
case
TargetPlatform
.
iOS
:
case
TargetPlatform
.
macOS
:
return
buildCupertinoSwitch
(
context
);
}
}
}
}
}
class
_SwitchRenderObjectWidget
extends
LeafRenderObjectWidget
{
const
_SwitchRenderObjectWidget
({
Key
?
key
,
required
this
.
value
,
required
this
.
activeColor
,
required
this
.
inactiveColor
,
required
this
.
hoverColor
,
required
this
.
focusColor
,
required
this
.
reactionColor
,
required
this
.
inactiveReactionColor
,
required
this
.
splashRadius
,
required
this
.
activeThumbImage
,
required
this
.
onActiveThumbImageError
,
required
this
.
inactiveThumbImage
,
required
this
.
onInactiveThumbImageError
,
required
this
.
activeTrackColor
,
required
this
.
inactiveTrackColor
,
required
this
.
configuration
,
required
this
.
onChanged
,
required
this
.
additionalConstraints
,
required
this
.
dragStartBehavior
,
required
this
.
hasFocus
,
required
this
.
hovering
,
required
this
.
state
,
required
this
.
surfaceColor
,
})
:
super
(
key:
key
);
final
bool
value
;
final
Color
activeColor
;
final
Color
inactiveColor
;
final
Color
hoverColor
;
final
Color
focusColor
;
final
Color
reactionColor
;
final
Color
inactiveReactionColor
;
final
double
splashRadius
;
final
ImageProvider
?
activeThumbImage
;
final
ImageErrorListener
?
onActiveThumbImageError
;
final
ImageProvider
?
inactiveThumbImage
;
final
ImageErrorListener
?
onInactiveThumbImageError
;
final
Color
activeTrackColor
;
final
Color
inactiveTrackColor
;
final
ImageConfiguration
configuration
;
final
ValueChanged
<
bool
>?
onChanged
;
final
BoxConstraints
additionalConstraints
;
final
DragStartBehavior
dragStartBehavior
;
final
bool
hasFocus
;
final
bool
hovering
;
final
_SwitchState
state
;
final
Color
surfaceColor
;
@override
_RenderSwitch
createRenderObject
(
BuildContext
context
)
{
return
_RenderSwitch
(
dragStartBehavior:
dragStartBehavior
,
value:
value
,
activeColor:
activeColor
,
inactiveColor:
inactiveColor
,
hoverColor:
hoverColor
,
focusColor:
focusColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
activeThumbImage:
activeThumbImage
,
onActiveThumbImageError:
onActiveThumbImageError
,
inactiveThumbImage:
inactiveThumbImage
,
onInactiveThumbImageError:
onInactiveThumbImageError
,
activeTrackColor:
activeTrackColor
,
inactiveTrackColor:
inactiveTrackColor
,
configuration:
configuration
,
onChanged:
onChanged
!=
null
?
_handleValueChanged
:
null
,
textDirection:
Directionality
.
of
(
context
),
additionalConstraints:
additionalConstraints
,
hasFocus:
hasFocus
,
hovering:
hovering
,
state:
state
,
surfaceColor:
surfaceColor
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderSwitch
renderObject
)
{
renderObject
..
value
=
value
..
activeColor
=
activeColor
..
inactiveColor
=
inactiveColor
..
hoverColor
=
hoverColor
..
focusColor
=
focusColor
..
reactionColor
=
reactionColor
..
inactiveReactionColor
=
inactiveReactionColor
..
splashRadius
=
splashRadius
..
activeThumbImage
=
activeThumbImage
..
onActiveThumbImageError
=
onActiveThumbImageError
..
inactiveThumbImage
=
inactiveThumbImage
..
onInactiveThumbImageError
=
onInactiveThumbImageError
..
activeTrackColor
=
activeTrackColor
..
inactiveTrackColor
=
inactiveTrackColor
..
configuration
=
configuration
..
onChanged
=
onChanged
!=
null
?
_handleValueChanged
:
null
..
textDirection
=
Directionality
.
of
(
context
)
..
additionalConstraints
=
additionalConstraints
..
dragStartBehavior
=
dragStartBehavior
..
hasFocus
=
hasFocus
..
hovering
=
hovering
..
vsync
=
state
..
surfaceColor
=
surfaceColor
;
}
void
_handleValueChanged
(
bool
?
value
)
{
// Wrap the onChanged callback because the RenderToggleable supports tri-state
// values (i.e. value can be null), but the Switch doesn't. We pass false
// for the tristate param to RenderToggleable, so value should never
// be null.
assert
(
value
!=
null
);
if
(
onChanged
!=
null
)
{
onChanged
!(
value
!);
}
}
}
}
class
_SwitchPainter
extends
ToggleablePainter
{
class
_RenderSwitch
extends
RenderToggleable
{
_RenderSwitch
({
required
bool
value
,
required
Color
activeColor
,
required
Color
inactiveColor
,
required
Color
hoverColor
,
required
Color
focusColor
,
required
Color
reactionColor
,
required
Color
inactiveReactionColor
,
required
double
splashRadius
,
required
ImageProvider
?
activeThumbImage
,
required
ImageErrorListener
?
onActiveThumbImageError
,
required
ImageProvider
?
inactiveThumbImage
,
required
ImageErrorListener
?
onInactiveThumbImageError
,
required
Color
activeTrackColor
,
required
Color
inactiveTrackColor
,
required
ImageConfiguration
configuration
,
required
BoxConstraints
additionalConstraints
,
required
TextDirection
textDirection
,
required
ValueChanged
<
bool
?>?
onChanged
,
required
DragStartBehavior
dragStartBehavior
,
required
bool
hasFocus
,
required
bool
hovering
,
required
this
.
state
,
required
Color
surfaceColor
,
})
:
assert
(
textDirection
!=
null
),
_activeThumbImage
=
activeThumbImage
,
_onActiveThumbImageError
=
onActiveThumbImageError
,
_inactiveThumbImage
=
inactiveThumbImage
,
_onInactiveThumbImageError
=
onInactiveThumbImageError
,
_activeTrackColor
=
activeTrackColor
,
_inactiveTrackColor
=
inactiveTrackColor
,
_configuration
=
configuration
,
_textDirection
=
textDirection
,
_surfaceColor
=
surfaceColor
,
super
(
value:
value
,
tristate:
false
,
activeColor:
activeColor
,
inactiveColor:
inactiveColor
,
hoverColor:
hoverColor
,
focusColor:
focusColor
,
reactionColor:
reactionColor
,
inactiveReactionColor:
inactiveReactionColor
,
splashRadius:
splashRadius
,
onChanged:
onChanged
,
additionalConstraints:
additionalConstraints
,
hasFocus:
hasFocus
,
hovering:
hovering
,
vsync:
state
,
)
{
_drag
=
HorizontalDragGestureRecognizer
()
..
onStart
=
_handleDragStart
..
onUpdate
=
_handleDragUpdate
..
onEnd
=
_handleDragEnd
..
dragStartBehavior
=
dragStartBehavior
;
}
ImageProvider
?
get
activeThumbImage
=>
_activeThumbImage
;
ImageProvider
?
get
activeThumbImage
=>
_activeThumbImage
;
ImageProvider
?
_activeThumbImage
;
ImageProvider
?
_activeThumbImage
;
set
activeThumbImage
(
ImageProvider
?
value
)
{
set
activeThumbImage
(
ImageProvider
?
value
)
{
if
(
value
==
_activeThumbImage
)
if
(
value
==
_activeThumbImage
)
return
;
return
;
_activeThumbImage
=
value
;
_activeThumbImage
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
ImageErrorListener
?
get
onActiveThumbImageError
=>
_onActiveThumbImageError
;
ImageErrorListener
?
get
onActiveThumbImageError
=>
_onActiveThumbImageError
;
...
@@ -765,7 +815,7 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -765,7 +815,7 @@ class _SwitchPainter extends ToggleablePainter {
return
;
return
;
}
}
_onActiveThumbImageError
=
value
;
_onActiveThumbImageError
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
ImageProvider
?
get
inactiveThumbImage
=>
_inactiveThumbImage
;
ImageProvider
?
get
inactiveThumbImage
=>
_inactiveThumbImage
;
...
@@ -774,7 +824,7 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -774,7 +824,7 @@ class _SwitchPainter extends ToggleablePainter {
if
(
value
==
_inactiveThumbImage
)
if
(
value
==
_inactiveThumbImage
)
return
;
return
;
_inactiveThumbImage
=
value
;
_inactiveThumbImage
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
ImageErrorListener
?
get
onInactiveThumbImageError
=>
_onInactiveThumbImageError
;
ImageErrorListener
?
get
onInactiveThumbImageError
=>
_onInactiveThumbImageError
;
...
@@ -784,77 +834,132 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -784,77 +834,132 @@ class _SwitchPainter extends ToggleablePainter {
return
;
return
;
}
}
_onInactiveThumbImageError
=
value
;
_onInactiveThumbImageError
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
Color
get
activeTrackColor
=>
_activeTrackColor
!
;
Color
get
activeTrackColor
=>
_activeTrackColor
;
Color
?
_activeTrackColor
;
Color
_activeTrackColor
;
set
activeTrackColor
(
Color
value
)
{
set
activeTrackColor
(
Color
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
null
);
if
(
value
==
_activeTrackColor
)
if
(
value
==
_activeTrackColor
)
return
;
return
;
_activeTrackColor
=
value
;
_activeTrackColor
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
Color
get
inactiveTrackColor
=>
_inactiveTrackColor
!
;
Color
get
inactiveTrackColor
=>
_inactiveTrackColor
;
Color
?
_inactiveTrackColor
;
Color
_inactiveTrackColor
;
set
inactiveTrackColor
(
Color
value
)
{
set
inactiveTrackColor
(
Color
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
null
);
if
(
value
==
_inactiveTrackColor
)
if
(
value
==
_inactiveTrackColor
)
return
;
return
;
_inactiveTrackColor
=
value
;
_inactiveTrackColor
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
ImageConfiguration
get
configuration
=>
_configuration
!
;
ImageConfiguration
get
configuration
=>
_configuration
;
ImageConfiguration
?
_configuration
;
ImageConfiguration
_configuration
;
set
configuration
(
ImageConfiguration
value
)
{
set
configuration
(
ImageConfiguration
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
null
);
if
(
value
==
_configuration
)
if
(
value
==
_configuration
)
return
;
return
;
_configuration
=
value
;
_configuration
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
TextDirection
get
textDirection
=>
_textDirection
!
;
TextDirection
get
textDirection
=>
_textDirection
;
TextDirection
?
_textDirection
;
TextDirection
_textDirection
;
set
textDirection
(
TextDirection
value
)
{
set
textDirection
(
TextDirection
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
null
);
if
(
_textDirection
==
value
)
if
(
_textDirection
==
value
)
return
;
return
;
_textDirection
=
value
;
_textDirection
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
Color
get
surfaceColor
=>
_surfaceColor
!;
DragStartBehavior
get
dragStartBehavior
=>
_drag
.
dragStartBehavior
;
Color
?
_surfaceColor
;
set
dragStartBehavior
(
DragStartBehavior
value
)
{
assert
(
value
!=
null
);
if
(
_drag
.
dragStartBehavior
==
value
)
return
;
_drag
.
dragStartBehavior
=
value
;
}
Color
get
surfaceColor
=>
_surfaceColor
;
Color
_surfaceColor
;
set
surfaceColor
(
Color
value
)
{
set
surfaceColor
(
Color
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
null
);
if
(
value
==
_surfaceColor
)
if
(
value
==
_surfaceColor
)
return
;
return
;
_surfaceColor
=
value
;
_surfaceColor
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
bool
get
isInteractive
=>
_isInteractive
!;
_SwitchState
state
;
bool
?
_isInteractive
;
set
isInteractive
(
bool
value
)
{
@override
if
(
value
==
_isInteractive
)
{
set
value
(
bool
?
newValue
)
{
return
;
assert
(
value
!=
null
);
super
.
value
=
newValue
;
// The widget is rebuilt and we have pending position animation to play.
if
(
_needsPositionAnimation
)
{
_needsPositionAnimation
=
false
;
position
.
reverseCurve
=
null
;
if
(
newValue
!)
positionController
.
forward
();
else
positionController
.
reverse
();
}
}
_isInteractive
=
value
;
notifyListeners
();
}
}
double
get
trackInnerLength
=>
_trackInnerLength
!;
@override
double
?
_trackInnerLength
;
void
detach
()
{
set
trackInnerLength
(
double
value
)
{
_cachedThumbPainter
?.
dispose
();
if
(
value
==
_trackInnerLength
)
{
_cachedThumbPainter
=
null
;
return
;
super
.
detach
();
}
double
get
_trackInnerLength
=>
size
.
width
-
_kSwitchMinSize
;
late
HorizontalDragGestureRecognizer
_drag
;
bool
_needsPositionAnimation
=
false
;
void
_handleDragStart
(
DragStartDetails
details
)
{
if
(
isInteractive
)
reactionController
.
forward
();
}
void
_handleDragUpdate
(
DragUpdateDetails
details
)
{
if
(
isInteractive
)
{
position
.
reverseCurve
=
null
;
final
double
delta
=
details
.
primaryDelta
!
/
_trackInnerLength
;
switch
(
textDirection
)
{
case
TextDirection
.
rtl
:
positionController
.
value
-=
delta
;
break
;
case
TextDirection
.
ltr
:
positionController
.
value
+=
delta
;
break
;
}
}
}
_trackInnerLength
=
value
;
}
notifyListeners
();
void
_handleDragEnd
(
DragEndDetails
details
)
{
_needsPositionAnimation
=
true
;
if
(
position
.
value
>=
0.5
!=
value
)
onChanged
!(!
value
!);
reactionController
.
reverse
();
state
.
_didFinishDragging
();
}
@override
void
handleEvent
(
PointerEvent
event
,
BoxHitTestEntry
entry
)
{
assert
(
debugHandleEvent
(
event
,
entry
));
if
(
event
is
PointerDownEvent
&&
onChanged
!=
null
)
_drag
.
addPointer
(
event
);
super
.
handleEvent
(
event
,
entry
);
}
}
Color
?
_cachedThumbColor
;
Color
?
_cachedThumbColor
;
...
@@ -879,12 +984,19 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -879,12 +984,19 @@ class _SwitchPainter extends ToggleablePainter {
// are already in the middle of painting. (In fact, doing so would trigger
// are already in the middle of painting. (In fact, doing so would trigger
// an assert).
// an assert).
if
(!
_isPainting
)
if
(!
_isPainting
)
notifyListeners
();
markNeedsPaint
();
}
@override
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
super
.
describeSemanticsConfiguration
(
config
);
config
.
isToggled
=
value
==
true
;
}
}
@override
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
final
bool
isEnabled
=
isInteractive
;
final
Canvas
canvas
=
context
.
canvas
;
final
bool
isEnabled
=
onChanged
!=
null
;
final
double
currentValue
=
position
.
value
;
final
double
currentValue
=
position
.
value
;
final
double
visualPosition
;
final
double
visualPosition
;
...
@@ -917,8 +1029,8 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -917,8 +1029,8 @@ class _SwitchPainter extends ToggleablePainter {
..
color
=
trackColor
;
..
color
=
trackColor
;
const
double
trackHorizontalPadding
=
kRadialReactionRadius
-
_kTrackRadius
;
const
double
trackHorizontalPadding
=
kRadialReactionRadius
-
_kTrackRadius
;
final
Rect
trackRect
=
Rect
.
fromLTWH
(
final
Rect
trackRect
=
Rect
.
fromLTWH
(
trackHorizontalPadding
,
offset
.
dx
+
trackHorizontalPadding
,
(
size
.
height
-
_kTrackHeight
)
/
2.0
,
offset
.
dy
+
(
size
.
height
-
_kTrackHeight
)
/
2.0
,
size
.
width
-
2.0
*
trackHorizontalPadding
,
size
.
width
-
2.0
*
trackHorizontalPadding
,
_kTrackHeight
,
_kTrackHeight
,
);
);
...
@@ -926,11 +1038,11 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -926,11 +1038,11 @@ class _SwitchPainter extends ToggleablePainter {
canvas
.
drawRRect
(
trackRRect
,
paint
);
canvas
.
drawRRect
(
trackRRect
,
paint
);
final
Offset
thumbPosition
=
Offset
(
final
Offset
thumbPosition
=
Offset
(
kRadialReactionRadius
+
visualPosition
*
trackInnerLength
,
kRadialReactionRadius
+
visualPosition
*
_
trackInnerLength
,
size
.
height
/
2.0
,
size
.
height
/
2.0
,
);
);
paintRadialReaction
(
canvas
:
canvas
,
origin:
thumbPosition
);
paintRadialReaction
(
canvas
,
offset
,
thumbPosition
);
try
{
try
{
_isPainting
=
true
;
_isPainting
=
true
;
...
@@ -947,7 +1059,7 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -947,7 +1059,7 @@ class _SwitchPainter extends ToggleablePainter {
final
double
radius
=
_kThumbRadius
-
inset
;
final
double
radius
=
_kThumbRadius
-
inset
;
thumbPainter
.
paint
(
thumbPainter
.
paint
(
canvas
,
canvas
,
thumbPosition
-
Offset
(
radius
,
radius
),
thumbPosition
+
offset
-
Offset
(
radius
,
radius
),
configuration
.
copyWith
(
size:
Size
.
fromRadius
(
radius
)),
configuration
.
copyWith
(
size:
Size
.
fromRadius
(
radius
)),
);
);
}
finally
{
}
finally
{
...
...
packages/flutter/lib/src/material/toggleable.dart
View file @
328a262e
...
@@ -6,10 +6,9 @@ import 'package:flutter/animation.dart';
...
@@ -6,10 +6,9 @@ import 'package:flutter/animation.dart';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.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/
scheduler
.dart'
;
import
'constants.dart'
;
import
'constants.dart'
;
import
'material_state.dart'
;
// Duration of the animation that moves the toggle from one state to another.
// Duration of the animation that moves the toggle from one state to another.
const
Duration
_kToggleDuration
=
Duration
(
milliseconds:
200
);
const
Duration
_kToggleDuration
=
Duration
(
milliseconds:
200
);
...
@@ -17,21 +16,92 @@ const Duration _kToggleDuration = Duration(milliseconds: 200);
...
@@ -17,21 +16,92 @@ const Duration _kToggleDuration = Duration(milliseconds: 200);
// Duration of the fade animation for the reaction when focus and hover occur.
// Duration of the fade animation for the reaction when focus and hover occur.
const
Duration
_kReactionFadeDuration
=
Duration
(
milliseconds:
50
);
const
Duration
_kReactionFadeDuration
=
Duration
(
milliseconds:
50
);
/// A mixin for [StatefulWidget]s that implement material-themed toggleable
/// A base class for material style toggleable controls with toggle animations.
/// controls with toggle animations (e.g. [Switch]es, [Checkbox]es, and
/// [Radio]s).
///
///
/// The mixin implements the logic for toggling the control (e.g. when tapped)
/// This class handles storing the current value, dispatching ValueChanged on a
/// and provides a series of animation controllers to transition the control
/// tap gesture and driving a changed animation. Subclasses are responsible for
/// from one state to another. It does not have any opinion about the visual
/// painting.
/// representation of the toggleable widget. The visuals are defined by a
abstract
class
RenderToggleable
extends
RenderConstrainedBox
{
/// [CustomPainter] passed to the [buildToggleable]. [State] objects using this
/// Creates a toggleable render object.
/// mixin should call that method from their [build] method.
///
///
/// The [activeColor], and [inactiveColor] arguments must not be
/// This mixin is used to implement the material components for [Switch],
/// null. The [value] can only be null if tristate is true.
/// [Checkbox], and [Radio] controls.
RenderToggleable
({
@optionalTypeArgs
required
bool
?
value
,
mixin
ToggleableStateMixin
<
S
extends
StatefulWidget
>
on
TickerProviderStateMixin
<
S
>
{
bool
tristate
=
false
,
required
Color
activeColor
,
required
Color
inactiveColor
,
Color
?
hoverColor
,
Color
?
focusColor
,
Color
?
reactionColor
,
Color
?
inactiveReactionColor
,
required
double
splashRadius
,
ValueChanged
<
bool
?>?
onChanged
,
required
BoxConstraints
additionalConstraints
,
required
TickerProvider
vsync
,
bool
hasFocus
=
false
,
bool
hovering
=
false
,
})
:
assert
(
tristate
!=
null
),
assert
(
tristate
||
value
!=
null
),
assert
(
activeColor
!=
null
),
assert
(
inactiveColor
!=
null
),
assert
(
vsync
!=
null
),
_value
=
value
,
_tristate
=
tristate
,
_activeColor
=
activeColor
,
_inactiveColor
=
inactiveColor
,
_hoverColor
=
hoverColor
??
activeColor
.
withAlpha
(
kRadialReactionAlpha
),
_focusColor
=
focusColor
??
activeColor
.
withAlpha
(
kRadialReactionAlpha
),
_reactionColor
=
reactionColor
??
activeColor
.
withAlpha
(
kRadialReactionAlpha
),
_inactiveReactionColor
=
inactiveReactionColor
??
activeColor
.
withAlpha
(
kRadialReactionAlpha
),
_splashRadius
=
splashRadius
,
_onChanged
=
onChanged
,
_hasFocus
=
hasFocus
,
_hovering
=
hovering
,
_vsync
=
vsync
,
super
(
additionalConstraints:
additionalConstraints
)
{
_tap
=
TapGestureRecognizer
()
..
onTapDown
=
_handleTapDown
..
onTap
=
_handleTap
..
onTapUp
=
_handleTapUp
..
onTapCancel
=
_handleTapCancel
;
_positionController
=
AnimationController
(
duration:
_kToggleDuration
,
value:
value
==
false
?
0.0
:
1.0
,
vsync:
vsync
,
);
_position
=
CurvedAnimation
(
parent:
_positionController
,
curve:
Curves
.
linear
,
)..
addListener
(
markNeedsPaint
);
_reactionController
=
AnimationController
(
duration:
kRadialReactionDuration
,
vsync:
vsync
,
);
_reaction
=
CurvedAnimation
(
parent:
_reactionController
,
curve:
Curves
.
fastOutSlowIn
,
)..
addListener
(
markNeedsPaint
);
_reactionHoverFadeController
=
AnimationController
(
duration:
_kReactionFadeDuration
,
value:
hovering
||
hasFocus
?
1.0
:
0.0
,
vsync:
vsync
,
);
_reactionHoverFade
=
CurvedAnimation
(
parent:
_reactionHoverFadeController
,
curve:
Curves
.
fastOutSlowIn
,
)..
addListener
(
markNeedsPaint
);
_reactionFocusFadeController
=
AnimationController
(
duration:
_kReactionFadeDuration
,
value:
hovering
||
hasFocus
?
1.0
:
0.0
,
vsync:
vsync
,
);
_reactionFocusFade
=
CurvedAnimation
(
parent:
_reactionFocusFadeController
,
curve:
Curves
.
fastOutSlowIn
,
)..
addListener
(
markNeedsPaint
);
}
/// Used by subclasses to manipulate the visual value of the control.
/// Used by subclasses to manipulate the visual value of the control.
///
///
/// Some controls respond to user input by updating their visual value. For
/// Some controls respond to user input by updating their visual value. For
...
@@ -39,15 +109,16 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
...
@@ -39,15 +109,16 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
/// dragged. These controls manipulate this animation controller to update
/// dragged. These controls manipulate this animation controller to update
/// their [position] and eventually trigger an [onChanged] callback when the
/// their [position] and eventually trigger an [onChanged] callback when the
/// animation reaches either 0.0 or 1.0.
/// animation reaches either 0.0 or 1.0.
@protected
AnimationController
get
positionController
=>
_positionController
;
AnimationController
get
positionController
=>
_positionController
;
late
AnimationController
_positionController
;
late
AnimationController
_positionController
;
/// The visual value of the control.
/// The visual value of the control.
///
///
/// When the control is inactive, the [value] is false and this animation has
/// When the control is inactive, the [value] is false and this animation has
/// the value 0.0. When the control is active, the value
is either true or
/// the value 0.0. When the control is active, the value
either true or tristate
///
tristate is true and the value is null. When the control is active the
///
is true and the value is null. When the control is active the animation
///
animation
has a value of 1.0. When the control is changing from inactive
/// has a value of 1.0. When the control is changing from inactive
/// to active (or vice versa), [value] is the target value and this animation
/// to active (or vice versa), [value] is the target value and this animation
/// gradually updates from 0.0 to 1.0 (or vice versa).
/// gradually updates from 0.0 to 1.0 (or vice versa).
CurvedAnimation
get
position
=>
_position
;
CurvedAnimation
get
position
=>
_position
;
...
@@ -58,66 +129,84 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
...
@@ -58,66 +129,84 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
/// Some controls have a radial ink reaction to user input. This animation
/// Some controls have a radial ink reaction to user input. This animation
/// controller can be used to start or stop these ink reactions.
/// controller can be used to start or stop these ink reactions.
///
///
/// To paint the actual radial reaction, [ToggleablePainter.paintRadialReaction]
/// Subclasses should call [paintRadialReaction] to actually paint the radial
/// may be used.
/// reaction.
@protected
AnimationController
get
reactionController
=>
_reactionController
;
AnimationController
get
reactionController
=>
_reactionController
;
late
AnimationController
_reactionController
;
late
AnimationController
_reactionController
;
late
Animation
<
double
>
_reaction
;
/// The visual value of the radial reaction animation.
/// Used by subclasses to control the radial reaction's opacity animation for
/// [hasFocus] changes.
///
///
/// Some controls have a radial ink reaction to user input. This animation
/// Some controls have a radial ink reaction to focus. This animation
/// controls the progress of these ink reactions.
/// controller can be used to start or stop these ink reaction fade-ins and
/// fade-outs.
///
///
/// To paint the actual radial reaction, [ToggleablePainter.paintRadialReaction]
/// Subclasses should call [paintRadialReaction] to actually paint the radial
/// may be used.
/// reaction.
Animation
<
double
>
get
reaction
=>
_reaction
;
@protected
late
Animation
<
double
>
_reaction
;
AnimationController
get
reactionFocusFadeController
=>
_reactionFocusFadeController
;
late
AnimationController
_reactionFocusFadeController
;
late
Animation
<
double
>
_reactionFocusFade
;
/// Controls the radial reaction's opacity animation for hover changes.
/// Used by subclasses to control the radial reaction's opacity animation for
/// [hovering] changes.
///
///
/// Some controls have a radial ink reaction to pointer hover. This animation
/// Some controls have a radial ink reaction to pointer hover. This animation
/// control
s
these ink reaction fade-ins and
/// control
ler can be used to start or stop
these ink reaction fade-ins and
/// fade-outs.
/// fade-outs.
///
///
///
To paint the actual radial reaction, [ToggleablePainter.paintRadialReaction]
///
Subclasses should call [paintRadialReaction] to actually paint the radial
///
may be used
.
///
reaction
.
Animation
<
double
>
get
reactionHoverFade
=>
_reactionHoverFade
;
@protected
late
Animation
<
double
>
_reactionHoverFade
;
AnimationController
get
reactionHoverFadeController
=>
_reactionHoverFadeController
;
late
AnimationController
_reactionHoverFadeController
;
late
AnimationController
_reactionHoverFadeController
;
late
Animation
<
double
>
_reactionHoverFade
;
/// Controls the radial reaction's opacity animation for focus changes.
/// True if this toggleable has the input focus.
///
bool
get
hasFocus
=>
_hasFocus
;
/// Some controls have a radial ink reaction to focus. This animation
bool
_hasFocus
;
/// controls these ink reaction fade-ins and fade-outs.
set
hasFocus
(
bool
value
)
{
///
assert
(
value
!=
null
);
/// To paint the actual radial reaction, [ToggleablePainter.paintRadialReaction]
if
(
value
==
_hasFocus
)
/// may be used.
return
;
Animation
<
double
>
get
reactionFocusFade
=>
_reactionFocusFade
;
_hasFocus
=
value
;
late
Animation
<
double
>
_reactionFocusFade
;
if
(
_hasFocus
)
{
late
AnimationController
_reactionFocusFadeController
;
_reactionFocusFadeController
.
forward
();
}
else
{
/// Whether [value] of this control can be changed by user interaction.
_reactionFocusFadeController
.
reverse
();
///
}
/// The control is considered interactive if the [onChanged] callback is
markNeedsPaint
();
/// non-null. If the callback is null, then the control is disabled, and
}
/// non-interactive. A disabled checkbox, for example, is displayed using a
/// grey color and its value cannot be changed.
bool
get
isInteractive
=>
onChanged
!=
null
;
late
final
Map
<
Type
,
Action
<
Intent
>>
_actionMap
=
<
Type
,
Action
<
Intent
>>{
/// True if this toggleable is being hovered over by a pointer.
ActivateIntent:
CallbackAction
<
ActivateIntent
>(
onInvoke:
_handleTap
),
bool
get
hovering
=>
_hovering
;
};
bool
_hovering
;
set
hovering
(
bool
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_hovering
)
return
;
_hovering
=
value
;
if
(
_hovering
)
{
_reactionHoverFadeController
.
forward
();
}
else
{
_reactionHoverFadeController
.
reverse
();
}
markNeedsPaint
();
}
/// Called when the control changes value.
/// The [TickerProvider] for the [AnimationController]s that run the animations.
///
TickerProvider
get
vsync
=>
_vsync
;
/// If the control is tapped, [onChanged] is called immediately with the new
TickerProvider
_vsync
;
/// value.
set
vsync
(
TickerProvider
value
)
{
///
assert
(
value
!=
null
);
/// The control is considered interactive (see [isInteractive]) if this
if
(
value
==
_vsync
)
/// callback is non-null. If the callback is null, then the control is
return
;
/// disabled, and non-interactive. A disabled checkbox, for example, is
_vsync
=
value
;
/// displayed using a grey color and its value cannot be changed.
positionController
.
resync
(
vsync
);
ValueChanged
<
bool
?>?
get
onChanged
;
reactionController
.
resync
(
vsync
);
}
/// False if this control is "inactive" (not checked, off, or unselected).
/// False if this control is "inactive" (not checked, off, or unselected).
///
///
...
@@ -128,62 +217,17 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
...
@@ -128,62 +217,17 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
/// When the value changes, this object starts the [positionController] and
/// When the value changes, this object starts the [positionController] and
/// [position] animations to animate the visual appearance of the control to
/// [position] animations to animate the visual appearance of the control to
/// the new value.
/// the new value.
bool
?
get
value
;
bool
?
get
value
=>
_value
;
bool
?
_value
;
/// If true, [value] can be true, false, or null, otherwise [value] must
set
value
(
bool
?
value
)
{
/// be true or false.
assert
(
tristate
||
value
!=
null
);
///
if
(
value
==
_value
)
/// When [tristate] is true and [value] is null, then the control is
return
;
/// considered to be in its third or "indeterminate" state.
_value
=
value
;
bool
get
tristate
;
markNeedsSemanticsUpdate
();
_position
@override
..
curve
=
Curves
.
easeIn
void
initState
()
{
..
reverseCurve
=
Curves
.
easeOut
;
super
.
initState
();
_positionController
=
AnimationController
(
duration:
_kToggleDuration
,
value:
value
==
false
?
0.0
:
1.0
,
vsync:
this
,
);
_position
=
CurvedAnimation
(
parent:
_positionController
,
curve:
Curves
.
easeIn
,
reverseCurve:
Curves
.
easeOut
,
);
_reactionController
=
AnimationController
(
duration:
kRadialReactionDuration
,
vsync:
this
,
);
_reaction
=
CurvedAnimation
(
parent:
_reactionController
,
curve:
Curves
.
fastOutSlowIn
,
);
_reactionHoverFadeController
=
AnimationController
(
duration:
_kReactionFadeDuration
,
value:
_hovering
||
_focused
?
1.0
:
0.0
,
vsync:
this
,
);
_reactionHoverFade
=
CurvedAnimation
(
parent:
_reactionHoverFadeController
,
curve:
Curves
.
fastOutSlowIn
,
);
_reactionFocusFadeController
=
AnimationController
(
duration:
_kReactionFadeDuration
,
value:
_hovering
||
_focused
?
1.0
:
0.0
,
vsync:
this
,
);
_reactionFocusFade
=
CurvedAnimation
(
parent:
_reactionFocusFadeController
,
curve:
Curves
.
fastOutSlowIn
,
);
}
/// Runs the [position] animation to transition the Toggleable's appearance
/// to match [value].
///
/// This method must be called whenever [value] changes to ensure that the
/// visual representation of the Toggleable matches the current [value].
void
animateToValue
()
{
if
(
tristate
)
{
if
(
tristate
)
{
if
(
value
==
null
)
if
(
value
==
null
)
_positionController
.
value
=
0.0
;
_positionController
.
value
=
0.0
;
...
@@ -199,235 +243,94 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
...
@@ -199,235 +243,94 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin
}
}
}
}
@override
/// If true, [value] can be true, false, or null, otherwise [value] must
void
dispose
()
{
/// be true or false.
_positionController
.
dispose
();
_reactionController
.
dispose
();
_reactionHoverFadeController
.
dispose
();
_reactionFocusFadeController
.
dispose
();
super
.
dispose
();
}
/// The most recent [Offset] at which a pointer touched the Toggleable.
///
///
/// This is null if currently no pointer is touching the Toggleable or if
/// When [tristate] is true and [value] is null, then the control is
/// [isInteractive] is false.
/// considered to be in its third or "indeterminate" state.
Offset
?
get
downPosition
=>
_downPosition
;
bool
get
tristate
=>
_tristate
;
Offset
?
_downPosition
;
bool
_tristate
;
set
tristate
(
bool
value
)
{
void
_handleTapDown
(
TapDownDetails
details
)
{
assert
(
tristate
!=
null
);
if
(
isInteractive
)
{
if
(
value
==
_tristate
)
setState
(()
{
_downPosition
=
details
.
localPosition
;
});
_reactionController
.
forward
();
}
}
void
_handleTap
([
Intent
?
_
])
{
if
(!
isInteractive
)
return
;
return
;
switch
(
value
)
{
_tristate
=
value
;
case
false
:
markNeedsSemanticsUpdate
();
onChanged
!(
true
);
break
;
case
true
:
onChanged
!(
tristate
?
null
:
false
);
break
;
case
null
:
onChanged
!(
false
);
break
;
}
context
.
findRenderObject
()!.
sendSemanticsEvent
(
const
TapSemanticEvent
());
}
void
_handleTapEnd
([
TapUpDetails
?
_
])
{
if
(
_downPosition
!=
null
)
{
setState
(()
{
_downPosition
=
null
;
});
}
_reactionController
.
reverse
();
}
bool
_focused
=
false
;
void
_handleFocusHighlightChanged
(
bool
focused
)
{
if
(
focused
!=
_focused
)
{
setState
(()
{
_focused
=
focused
;
});
if
(
focused
)
{
_reactionFocusFadeController
.
forward
();
}
else
{
_reactionFocusFadeController
.
reverse
();
}
}
}
bool
_hovering
=
false
;
void
_handleHoverChanged
(
bool
hovering
)
{
if
(
hovering
!=
_hovering
)
{
setState
(()
{
_hovering
=
hovering
;
});
if
(
hovering
)
{
_reactionHoverFadeController
.
forward
();
}
else
{
_reactionHoverFadeController
.
reverse
();
}
}
}
/// Describes the current [MaterialState] of the Toggleable.
///
/// The returned set will include:
///
/// * [MaterialState.disabled], if [isInteractive] is false
/// * [MaterialState.hovered], if a pointer is hovering over the Toggleable
/// * [MaterialState.focused], if the Toggleable has input focus
/// * [MaterialState.selected], if [value] is true or null
Set
<
MaterialState
>
get
states
=>
<
MaterialState
>{
if
(!
isInteractive
)
MaterialState
.
disabled
,
if
(
_hovering
)
MaterialState
.
hovered
,
if
(
_focused
)
MaterialState
.
focused
,
if
(
value
!=
false
)
MaterialState
.
selected
,
};
/// Typically wraps a `painter` that draws the actual visuals of the
/// Toggleable with logic to toggle it.
///
/// Consider providing a subclass of [ToggleablePainter] as a `painter`, which
/// implements logic to draw a radial ink reaction for this control. The
/// painter is usually configured with the [reaction], [position],
/// [reactionHoverFade], and [reactionFocusFade] animation provided by this
/// mixin. It is expected to draw the visuals of the Toggleable based on the
/// current value of these animations. The animations are triggered by
/// this mixin to transition the Toggleable from one state to another.
///
/// This method must be called from the [build] method of the [State] class
/// that uses this mixin. The returned [Widget] must be returned from the
/// build method - potentially after wrapping it in other widgets.
Widget
buildToggleable
({
FocusNode
?
focusNode
,
bool
autofocus
=
false
,
required
MaterialStateProperty
<
MouseCursor
>
mouseCursor
,
required
Size
size
,
required
CustomPainter
painter
,
})
{
return
FocusableActionDetector
(
actions:
_actionMap
,
focusNode:
focusNode
,
autofocus:
autofocus
,
enabled:
isInteractive
,
onShowFocusHighlight:
_handleFocusHighlightChanged
,
onShowHoverHighlight:
_handleHoverChanged
,
mouseCursor:
mouseCursor
.
resolve
(
states
),
child:
GestureDetector
(
excludeFromSemantics:
!
isInteractive
,
onTapDown:
_handleTapDown
,
onTap:
_handleTap
,
onTapUp:
_handleTapEnd
,
onTapCancel:
_handleTapEnd
,
child:
Semantics
(
enabled:
isInteractive
,
child:
CustomPaint
(
size:
size
,
painter:
painter
,
),
),
),
);
}
}
}
/// A base class for a [CustomPainter] that may be passed to
/// The color that should be used in the active state (i.e., when [value] is true).
/// [ToggleableStateMixin.buildToggleable] to draw the visual representation of
/// a Toggleable.
///
/// Subclasses must implement the [paint] method to draw the actual visuals of
/// the Toggleable. In their [paint] method subclasses may call
/// [paintRadialReaction] to draw a radial ink reaction for this control.
abstract
class
ToggleablePainter
extends
ChangeNotifier
implements
CustomPainter
{
/// The visual value of the control.
///
///
/// Usually set to [ToggleableStateMixin.position].
/// For example, a checkbox should use this color when checked.
Animation
<
double
>
get
position
=>
_position
!;
Color
get
activeColor
=>
_activeColor
;
Animation
<
double
>?
_position
;
Color
_activeColor
;
set
position
(
Animation
<
double
>
value
)
{
set
activeColor
(
Color
value
)
{
if
(
value
==
_position
)
{
assert
(
value
!=
null
);
if
(
value
==
_activeColor
)
return
;
return
;
}
_activeColor
=
value
;
_position
?.
removeListener
(
notifyListeners
);
markNeedsPaint
();
value
.
addListener
(
notifyListeners
);
_position
=
value
;
notifyListeners
();
}
}
/// The
visual value of the radial reaction animation
.
/// The
color that should be used in the inactive state (i.e., when [value] is false)
.
///
///
/// Usually set to [ToggleableStateMixin.reaction].
/// For example, a checkbox should use this color when unchecked.
Animation
<
double
>
get
reaction
=>
_reaction
!;
Color
get
inactiveColor
=>
_inactiveColor
;
Animation
<
double
>?
_reaction
;
Color
_inactiveColor
;
set
reaction
(
Animation
<
double
>
value
)
{
set
inactiveColor
(
Color
value
)
{
if
(
value
==
_reaction
)
{
assert
(
value
!=
null
);
if
(
value
==
_inactiveColor
)
return
;
return
;
}
_inactiveColor
=
value
;
_reaction
?.
removeListener
(
notifyListeners
);
markNeedsPaint
();
value
.
addListener
(
notifyListeners
);
_reaction
=
value
;
notifyListeners
();
}
}
///
Controls the radial reaction's opacity animation for focus changes
.
///
The color that should be used for the reaction when [hovering] is true
.
///
///
/// Usually set to [ToggleableStateMixin.reactionFocusFade].
/// Used when the toggleable needs to change the reaction color/transparency,
Animation
<
double
>
get
reactionFocusFade
=>
_reactionFocusFade
!;
/// when it is being hovered over.
Animation
<
double
>?
_reactionFocusFade
;
set
reactionFocusFade
(
Animation
<
double
>
value
)
{
if
(
value
==
_reactionFocusFade
)
{
return
;
}
_reactionFocusFade
?.
removeListener
(
notifyListeners
);
value
.
addListener
(
notifyListeners
);
_reactionFocusFade
=
value
;
notifyListeners
();
}
/// Controls the radial reaction's opacity animation for hover changes.
///
///
/// Usually set to [ToggleableStateMixin.reactionHoverFade].
/// Defaults to the [activeColor] at alpha [kRadialReactionAlpha].
Animation
<
double
>
get
reactionHoverFade
=>
_reactionHoverFade
!;
Color
get
hoverColor
=>
_hoverColor
;
Animation
<
double
>?
_reactionHoverFade
;
Color
_hoverColor
;
set
reactionHoverFade
(
Animation
<
double
>
value
)
{
set
hoverColor
(
Color
value
)
{
if
(
value
==
_reactionHoverFade
)
{
assert
(
value
!=
null
);
if
(
value
==
_hoverColor
)
return
;
return
;
}
_hoverColor
=
value
;
_reactionHoverFade
?.
removeListener
(
notifyListeners
);
markNeedsPaint
();
value
.
addListener
(
notifyListeners
);
_reactionHoverFade
=
value
;
notifyListeners
();
}
}
/// The color that should be used in the active state (i.e., when
/// The color that should be used for the reaction when [hasFocus] is true.
/// [ToggleableStateMixin.value] is true).
///
///
/// For example, a checkbox should use this color when checked.
/// Used when the toggleable needs to change the reaction color/transparency,
Color
get
activeColor
=>
_activeColor
!;
/// when it has focus.
Color
?
_activeColor
;
///
set
activeColor
(
Color
value
)
{
/// Defaults to the [activeColor] at alpha [kRadialReactionAlpha].
if
(
_activeColor
==
value
)
{
Color
get
focusColor
=>
_focusColor
;
Color
_focusColor
;
set
focusColor
(
Color
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_focusColor
)
return
;
return
;
}
_focusColor
=
value
;
_activeColor
=
value
;
markNeedsPaint
();
notifyListeners
();
}
}
/// The color that should be used
in the inactive state (i.e., when
/// The color that should be used
for the reaction when the toggleable is
///
[ToggleableStateMixin.value] is false)
.
///
active
.
///
///
/// For example, a checkbox should use this color when unchecked.
/// Used when the toggleable needs to change the reaction color/transparency
Color
get
inactiveColor
=>
_inactiveColor
!;
/// that is displayed when the toggleable is active and tapped.
Color
?
_inactiveColor
;
///
set
inactiveColor
(
Color
value
)
{
/// Defaults to the [activeColor] at alpha [kRadialReactionAlpha].
if
(
_inactiveColor
==
value
)
{
Color
?
get
reactionColor
=>
_reactionColor
;
Color
?
_reactionColor
;
set
reactionColor
(
Color
?
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_reactionColor
)
return
;
return
;
}
_reactionColor
=
value
;
_inactiveColor
=
value
;
markNeedsPaint
();
notifyListeners
();
}
}
/// The color that should be used for the reaction when the toggleable is
/// The color that should be used for the reaction when the toggleable is
...
@@ -435,161 +338,184 @@ abstract class ToggleablePainter extends ChangeNotifier implements CustomPainter
...
@@ -435,161 +338,184 @@ abstract class ToggleablePainter extends ChangeNotifier implements CustomPainter
///
///
/// Used when the toggleable needs to change the reaction color/transparency
/// Used when the toggleable needs to change the reaction color/transparency
/// that is displayed when the toggleable is inactive and tapped.
/// that is displayed when the toggleable is inactive and tapped.
Color
get
inactiveReactionColor
=>
_inactiveReactionColor
!;
///
/// Defaults to the [activeColor] at alpha [kRadialReactionAlpha].
Color
?
get
inactiveReactionColor
=>
_inactiveReactionColor
;
Color
?
_inactiveReactionColor
;
Color
?
_inactiveReactionColor
;
set
inactiveReactionColor
(
Color
value
)
{
set
inactiveReactionColor
(
Color
?
value
)
{
if
(
value
==
_inactiveReactionColor
)
{
assert
(
value
!=
null
);
if
(
value
==
_inactiveReactionColor
)
return
;
return
;
}
_inactiveReactionColor
=
value
;
_inactiveReactionColor
=
value
;
notifyListeners
();
markNeedsPaint
();
}
}
/// The color that should be used for the reaction when the toggleable is
/// The splash radius for the radial reaction.
/// active.
double
get
splashRadius
=>
_splashRadius
;
///
double
_splashRadius
;
/// Used when the toggleable needs to change the reaction color/transparency
set
splashRadius
(
double
value
)
{
/// that is displayed when the toggleable is active and tapped.
if
(
value
==
_splashRadius
)
Color
get
reactionColor
=>
_reactionColor
!;
Color
?
_reactionColor
;
set
reactionColor
(
Color
value
)
{
if
(
value
==
_reactionColor
)
{
return
;
return
;
}
_splashRadius
=
value
;
_reactionColor
=
value
;
markNeedsPaint
();
notifyListeners
();
}
}
///
The color that should be used for the reaction when [isHovered] is tr
ue.
///
Called when the control changes val
ue.
///
///
/// Used when the toggleable needs to change the reaction color/transparency,
/// If the control is tapped, [onChanged] is called immediately with the new
/// when it is being hovered over.
/// value.
Color
get
hoverColor
=>
_hoverColor
!;
///
Color
?
_hoverColor
;
/// The control is considered interactive (see [isInteractive]) if this
set
hoverColor
(
Color
value
)
{
/// callback is non-null. If the callback is null, then the control is
if
(
value
==
_hoverColor
)
{
/// disabled, and non-interactive. A disabled checkbox, for example, is
/// displayed using a grey color and its value cannot be changed.
ValueChanged
<
bool
?>?
get
onChanged
=>
_onChanged
;
ValueChanged
<
bool
?>?
_onChanged
;
set
onChanged
(
ValueChanged
<
bool
?>?
value
)
{
if
(
value
==
_onChanged
)
return
;
return
;
final
bool
wasInteractive
=
isInteractive
;
_onChanged
=
value
;
if
(
wasInteractive
!=
isInteractive
)
{
markNeedsPaint
();
markNeedsSemanticsUpdate
();
}
}
_hoverColor
=
value
;
notifyListeners
();
}
}
///
The color that should be used for the reaction when [isFocused] is true
.
///
Whether [value] of this control can be changed by user interaction
.
///
///
/// Used when the toggleable needs to change the reaction color/transparency,
/// The control is considered interactive if the [onChanged] callback is
/// when it has focus.
/// non-null. If the callback is null, then the control is disabled, and
Color
get
focusColor
=>
_focusColor
!;
/// non-interactive. A disabled checkbox, for example, is displayed using a
Color
?
_focusColor
;
/// grey color and its value cannot be changed.
set
focusColor
(
Color
value
)
{
bool
get
isInteractive
=>
onChanged
!=
null
;
if
(
value
==
_focusColor
)
{
return
;
late
TapGestureRecognizer
_tap
;
Offset
?
_downPosition
;
@override
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
if
(
value
==
false
)
_positionController
.
reverse
();
else
_positionController
.
forward
();
if
(
isInteractive
)
{
switch
(
_reactionController
.
status
)
{
case
AnimationStatus
.
forward
:
_reactionController
.
forward
();
break
;
case
AnimationStatus
.
reverse
:
_reactionController
.
reverse
();
break
;
case
AnimationStatus
.
dismissed
:
case
AnimationStatus
.
completed
:
// nothing to do
break
;
}
}
}
_focusColor
=
value
;
notifyListeners
();
}
}
/// The splash radius for the radial reaction.
@override
double
get
splashRadius
=>
_splashRadius
!;
void
detach
()
{
double
?
_splashRadius
;
_positionController
.
stop
();
set
splashRadius
(
double
value
)
{
_reactionController
.
stop
();
if
(
value
==
_splashRadius
)
{
_reactionHoverFadeController
.
stop
();
return
;
_reactionFocusFadeController
.
stop
();
}
super
.
detach
();
_splashRadius
=
value
;
notifyListeners
();
}
}
/// The [Offset] within the Toggleable at which a pointer touched the Toggleable.
void
_handleTapDown
(
TapDownDetails
details
)
{
///
if
(
isInteractive
)
{
/// This is null if currently no pointer is touching the Toggleable.
_downPosition
=
globalToLocal
(
details
.
globalPosition
);
///
_reactionController
.
forward
();
/// Usually set to [ToggleableStateMixin.downPosition].
Offset
?
get
downPosition
=>
_downPosition
;
Offset
?
_downPosition
;
set
downPosition
(
Offset
?
value
)
{
if
(
value
==
_downPosition
)
{
return
;
}
}
_downPosition
=
value
;
notifyListeners
();
}
}
/// True if this toggleable has the input focus.
void
_handleTap
()
{
bool
get
isFocused
=>
_isFocused
!;
if
(!
isInteractive
)
bool
?
_isFocused
;
set
isFocused
(
bool
?
value
)
{
if
(
value
==
_isFocused
)
{
return
;
return
;
switch
(
value
)
{
case
false
:
onChanged
!(
true
);
break
;
case
true
:
onChanged
!(
tristate
?
null
:
false
);
break
;
case
null
:
onChanged
!(
false
);
break
;
}
}
_isFocused
=
value
;
sendSemanticsEvent
(
const
TapSemanticEvent
());
notifyListeners
();
}
}
/// True if this toggleable is being hovered over by a pointer.
void
_handleTapUp
(
TapUpDetails
details
)
{
bool
get
isHovered
=>
_isHovered
!;
_downPosition
=
null
;
bool
?
_isHovered
;
if
(
isInteractive
)
set
isHovered
(
bool
?
value
)
{
_reactionController
.
reverse
();
if
(
value
==
_isHovered
)
{
}
return
;
}
void
_handleTapCancel
()
{
_isHovered
=
value
;
_downPosition
=
null
;
notifyListeners
();
if
(
isInteractive
)
_reactionController
.
reverse
();
}
@override
bool
hitTestSelf
(
Offset
position
)
=>
true
;
@override
void
handleEvent
(
PointerEvent
event
,
BoxHitTestEntry
entry
)
{
assert
(
debugHandleEvent
(
event
,
entry
));
if
(
event
is
PointerDownEvent
&&
isInteractive
)
_tap
.
addPointer
(
event
);
}
}
/// Used by subclasses to paint the radial ink reaction for this control.
/// Used by subclasses to paint the radial ink reaction for this control.
///
///
/// The reaction is painted on the given canvas at the given offset. The
/// The reaction is painted on the given canvas at the given offset. The
/// origin is the center point of the reaction (usually distinct from the
/// origin is the center point of the reaction (usually distinct from the
/// [downPosition] at which the user interacted with the control).
/// point at which the user interacted with the control, which is handled
void
paintRadialReaction
({
/// automatically).
required
Canvas
canvas
,
void
paintRadialReaction
(
Canvas
canvas
,
Offset
offset
,
Offset
origin
)
{
Offset
offset
=
Offset
.
zero
,
if
(!
_reaction
.
isDismissed
||
!
_reactionFocusFade
.
isDismissed
||
!
_reactionHoverFade
.
isDismissed
)
{
required
Offset
origin
,
})
{
if
(!
reaction
.
isDismissed
||
!
reactionFocusFade
.
isDismissed
||
!
reactionHoverFade
.
isDismissed
)
{
final
Paint
reactionPaint
=
Paint
()
final
Paint
reactionPaint
=
Paint
()
..
color
=
Color
.
lerp
(
..
color
=
Color
.
lerp
(
Color
.
lerp
(
Color
.
lerp
(
Color
.
lerp
(
inactiveReactionColor
,
reactionColor
,
position
.
value
),
Color
.
lerp
(
inactiveReactionColor
,
reactionColor
,
_
position
.
value
),
hoverColor
,
hoverColor
,
reactionHoverFade
.
value
,
_
reactionHoverFade
.
value
,
),
),
focusColor
,
focusColor
,
reactionFocusFade
.
value
,
_
reactionFocusFade
.
value
,
)!;
)!;
final
Offset
center
=
Offset
.
lerp
(
downPosition
??
origin
,
origin
,
reaction
.
value
)!;
final
Offset
center
=
Offset
.
lerp
(
_downPosition
??
origin
,
origin
,
_
reaction
.
value
)!;
final
Animatable
<
double
>
radialReactionRadiusTween
=
Tween
<
double
>(
final
Animatable
<
double
>
radialReactionRadiusTween
=
Tween
<
double
>(
begin:
0.0
,
begin:
0.0
,
end:
splashRadius
,
end:
splashRadius
,
);
);
final
double
reactionRadius
=
isFocused
||
isHovered
final
double
reactionRadius
=
hasFocus
||
hovering
?
splashRadius
?
splashRadius
:
radialReactionRadiusTween
.
evaluate
(
reaction
);
:
radialReactionRadiusTween
.
evaluate
(
_
reaction
);
if
(
reactionRadius
>
0.0
)
{
if
(
reactionRadius
>
0.0
)
{
canvas
.
drawCircle
(
center
+
offset
,
reactionRadius
,
reactionPaint
);
canvas
.
drawCircle
(
center
+
offset
,
reactionRadius
,
reactionPaint
);
}
}
}
}
}
}
@override
@override
void
dispose
()
{
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
_position
?.
removeListener
(
notifyListeners
);
super
.
describeSemanticsConfiguration
(
config
);
_reaction
?.
removeListener
(
notifyListeners
);
_reactionFocusFade
?.
removeListener
(
notifyListeners
);
_reactionHoverFade
?.
removeListener
(
notifyListeners
);
super
.
dispose
();
}
@override
bool
shouldRepaint
(
covariant
CustomPainter
oldDelegate
)
=>
true
;
@override
bool
?
hitTest
(
Offset
position
)
=>
null
;
@override
config
.
isEnabled
=
isInteractive
;
SemanticsBuilderCallback
?
get
semanticsBuilder
=>
null
;
if
(
isInteractive
)
config
.
onTap
=
_handleTap
;
}
@override
@override
bool
shouldRebuildSemantics
(
covariant
CustomPainter
oldDelegate
)
=>
false
;
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
FlagProperty
(
'value'
,
value:
value
,
ifTrue:
'checked'
,
ifFalse:
'unchecked'
,
showName:
true
));
properties
.
add
(
FlagProperty
(
'isInteractive'
,
value:
isInteractive
,
ifTrue:
'enabled'
,
ifFalse:
'disabled'
,
defaultValue:
true
));
}
}
}
packages/flutter/test/material/checkbox_test.dart
View file @
328a262e
...
@@ -99,7 +99,7 @@ void main() {
...
@@ -99,7 +99,7 @@ void main() {
),
),
));
));
expect
(
tester
.
getSemantics
(
find
.
by
Type
(
Checkbox
)),
matchesSemantics
(
expect
(
tester
.
getSemantics
(
find
.
by
WidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
)),
matchesSemantics
(
hasCheckedState:
true
,
hasCheckedState:
true
,
hasEnabledState:
true
,
hasEnabledState:
true
,
// isFocusable is delayed by 1 frame.
// isFocusable is delayed by 1 frame.
...
@@ -108,7 +108,7 @@ void main() {
...
@@ -108,7 +108,7 @@ void main() {
await
tester
.
pump
();
await
tester
.
pump
();
// isFocusable should be false now after the 1 frame delay.
// isFocusable should be false now after the 1 frame delay.
expect
(
tester
.
getSemantics
(
find
.
by
Type
(
Checkbox
)),
matchesSemantics
(
expect
(
tester
.
getSemantics
(
find
.
by
WidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
)),
matchesSemantics
(
hasCheckedState:
true
,
hasCheckedState:
true
,
hasEnabledState:
true
,
hasEnabledState:
true
,
));
));
...
@@ -120,7 +120,7 @@ void main() {
...
@@ -120,7 +120,7 @@ void main() {
),
),
));
));
expect
(
tester
.
getSemantics
(
find
.
by
Type
(
Checkbox
)),
matchesSemantics
(
expect
(
tester
.
getSemantics
(
find
.
by
WidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
)),
matchesSemantics
(
hasCheckedState:
true
,
hasCheckedState:
true
,
hasEnabledState:
true
,
hasEnabledState:
true
,
isChecked:
true
,
isChecked:
true
,
...
@@ -290,7 +290,7 @@ void main() {
...
@@ -290,7 +290,7 @@ void main() {
);
);
await
tester
.
tap
(
find
.
byType
(
Checkbox
));
await
tester
.
tap
(
find
.
byType
(
Checkbox
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
byType
(
Checkbox
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
byType
(
Focus
));
expect
(
checkboxValue
,
true
);
expect
(
checkboxValue
,
true
);
expect
(
semanticEvent
,
<
String
,
dynamic
>{
expect
(
semanticEvent
,
<
String
,
dynamic
>{
...
@@ -319,8 +319,10 @@ void main() {
...
@@ -319,8 +319,10 @@ void main() {
);
);
}
}
RenderBox
getCheckboxRenderer
()
{
RenderToggleable
getCheckboxRenderer
()
{
return
tester
.
renderObject
<
RenderBox
>(
find
.
byType
(
Checkbox
));
return
tester
.
renderObject
<
RenderToggleable
>(
find
.
byWidgetPredicate
((
Widget
widget
)
{
return
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
;
}));
}
}
await
tester
.
pumpWidget
(
buildFrame
(
false
));
await
tester
.
pumpWidget
(
buildFrame
(
false
));
...
@@ -375,8 +377,10 @@ void main() {
...
@@ -375,8 +377,10 @@ void main() {
);
);
}
}
RenderBox
getCheckboxRenderer
()
{
RenderToggleable
getCheckboxRenderer
()
{
return
tester
.
renderObject
<
RenderBox
>(
find
.
byType
(
Checkbox
));
return
tester
.
renderObject
<
RenderToggleable
>(
find
.
byWidgetPredicate
((
Widget
widget
)
{
return
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
;
}));
}
}
await
tester
.
pumpWidget
(
buildFrame
(
checkColor:
checkColor
));
await
tester
.
pumpWidget
(
buildFrame
(
checkColor:
checkColor
));
...
@@ -449,10 +453,11 @@ void main() {
...
@@ -449,10 +453,11 @@ void main() {
paints
paints
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
Colors
.
orange
[
500
])
..
drrect
(
..
drrect
(
color:
const
Color
(
0x8a000000
),
color:
const
Color
(
0x8a000000
),
outer:
RRect
.
fromLTRBR
(
15.0
,
15.0
,
33.0
,
33.0
,
const
Radius
.
circular
(
1.0
)),
outer:
RRect
.
fromLTRBR
(
inner:
RRect
.
fromLTRBR
(
17.0
,
17.0
,
31.0
,
31.0
,
const
Radius
.
circular
(-
1.0
)),
391.0
,
291.0
,
409.0
,
309.0
,
const
Radius
.
circular
(
1.0
)),
),
inner:
RRect
.
fromLTRBR
(
393.0
,
293.0
,
407.0
,
307.0
,
const
Radius
.
circular
(-
1.0
))),
);
);
// Check what happens when disabled.
// Check what happens when disabled.
...
@@ -464,10 +469,11 @@ void main() {
...
@@ -464,10 +469,11 @@ void main() {
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
paints
paints
..
drrect
(
..
drrect
(
color:
const
Color
(
0x61000000
),
color:
const
Color
(
0x61000000
),
outer:
RRect
.
fromLTRBR
(
15.0
,
15.0
,
33.0
,
33.0
,
const
Radius
.
circular
(
1.0
)),
outer:
RRect
.
fromLTRBR
(
inner:
RRect
.
fromLTRBR
(
17.0
,
17.0
,
31.0
,
31.0
,
const
Radius
.
circular
(-
1.0
)),
391.0
,
291.0
,
409.0
,
309.0
,
const
Radius
.
circular
(
1.0
)),
),
inner:
RRect
.
fromLTRBR
(
393.0
,
293.0
,
407.0
,
307.0
,
const
Radius
.
circular
(-
1.0
))),
);
);
});
});
...
@@ -819,8 +825,10 @@ void main() {
...
@@ -819,8 +825,10 @@ void main() {
);
);
}
}
RenderBox
getCheckboxRenderer
()
{
RenderToggleable
getCheckboxRenderer
()
{
return
tester
.
renderObject
<
RenderBox
>(
find
.
byType
(
Checkbox
));
return
tester
.
renderObject
<
RenderToggleable
>(
find
.
byWidgetPredicate
((
Widget
widget
)
{
return
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
;
}));
}
}
await
tester
.
pumpWidget
(
buildFrame
(
enabled:
true
));
await
tester
.
pumpWidget
(
buildFrame
(
enabled:
true
));
...
@@ -870,8 +878,10 @@ void main() {
...
@@ -870,8 +878,10 @@ void main() {
);
);
}
}
RenderBox
getCheckboxRenderer
()
{
RenderToggleable
getCheckboxRenderer
()
{
return
tester
.
renderObject
<
RenderBox
>(
find
.
byType
(
Checkbox
));
return
tester
.
renderObject
<
RenderToggleable
>(
find
.
byWidgetPredicate
((
Widget
widget
)
{
return
widget
.
runtimeType
.
toString
()
==
'_CheckboxRenderObjectWidget'
;
}));
}
}
await
tester
.
pumpWidget
(
buildFrame
());
await
tester
.
pumpWidget
(
buildFrame
());
...
@@ -927,9 +937,11 @@ void main() {
...
@@ -927,9 +937,11 @@ void main() {
paints
paints
..
drrect
(
..
drrect
(
color:
const
Color
(
0xfff44336
),
color:
const
Color
(
0xfff44336
),
outer:
RRect
.
fromLTRBR
(
15.0
,
15.0
,
33.0
,
33.0
,
const
Radius
.
circular
(
5
)),
outer:
RRect
.
fromLTRBR
(
inner:
RRect
.
fromLTRBR
(
19.0
,
19.0
,
29.0
,
29.0
,
const
Radius
.
circular
(
1
)),
391.0
,
291.0
,
409.0
,
309.0
,
const
Radius
.
circular
(
5
)),
),
inner:
RRect
.
fromLTRBR
(
395.0
,
295.0
,
405.0
,
305.0
,
const
Radius
.
circular
(
1
)))
,
);
);
});
});
...
@@ -1172,29 +1184,6 @@ void main() {
...
@@ -1172,29 +1184,6 @@ void main() {
await
gesture
.
up
();
await
gesture
.
up
();
});
});
testWidgets
(
'Do not crash when widget disappears while pointer is down'
,
(
WidgetTester
tester
)
async
{
Widget
buildCheckbox
(
bool
show
)
{
return
MaterialApp
(
home:
Material
(
child:
Center
(
child:
show
?
Checkbox
(
value:
true
,
onChanged:
(
_
)
{
})
:
Container
(),
),
),
);
}
await
tester
.
pumpWidget
(
buildCheckbox
(
true
));
final
Offset
center
=
tester
.
getCenter
(
find
.
byType
(
Checkbox
));
// Put a pointer down on the screen.
final
TestGesture
gesture
=
await
tester
.
startGesture
(
center
);
await
tester
.
pump
();
// While the pointer is down, the widget disappears.
await
tester
.
pumpWidget
(
buildCheckbox
(
false
));
expect
(
find
.
byType
(
Checkbox
),
findsNothing
);
// Release pointer after widget disappeared.
gesture
.
up
();
});
}
}
class
_SelectedGrabMouseCursor
extends
MaterialStateMouseCursor
{
class
_SelectedGrabMouseCursor
extends
MaterialStateMouseCursor
{
...
...
packages/flutter/test/material/radio_test.dart
View file @
328a262e
...
@@ -308,7 +308,7 @@ void main() {
...
@@ -308,7 +308,7 @@ void main() {
));
));
await
tester
.
tap
(
find
.
byKey
(
key
));
await
tester
.
tap
(
find
.
byKey
(
key
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
by
Key
(
key
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
by
Type
(
Focus
));
expect
(
radioValue
,
1
);
expect
(
radioValue
,
1
);
expect
(
semanticEvent
,
<
String
,
dynamic
>{
expect
(
semanticEvent
,
<
String
,
dynamic
>{
...
@@ -1078,29 +1078,4 @@ void main() {
...
@@ -1078,29 +1078,4 @@ void main() {
reason:
'Hovered Radio should use overlay color
$hoverOverlayColor
over
$hoverColor
'
,
reason:
'Hovered Radio should use overlay color
$hoverOverlayColor
over
$hoverColor
'
,
);
);
});
});
testWidgets
(
'Do not crash when widget disappears while pointer is down'
,
(
WidgetTester
tester
)
async
{
final
Key
key
=
UniqueKey
();
Widget
buildRadio
(
bool
show
)
{
return
MaterialApp
(
home:
Material
(
child:
Center
(
child:
show
?
Radio
<
bool
>(
key:
key
,
value:
true
,
groupValue:
false
,
onChanged:
(
_
)
{
})
:
Container
(),
)
),
);
}
await
tester
.
pumpWidget
(
buildRadio
(
true
));
final
Offset
center
=
tester
.
getCenter
(
find
.
byKey
(
key
));
// Put a pointer down on the screen.
final
TestGesture
gesture
=
await
tester
.
startGesture
(
center
);
await
tester
.
pump
();
// While the pointer is down, the widget disappears.
await
tester
.
pumpWidget
(
buildRadio
(
false
));
expect
(
find
.
byKey
(
key
),
findsNothing
);
// Release pointer after widget disappeared.
gesture
.
up
();
});
}
}
packages/flutter/test/material/switch_list_tile_test.dart
View file @
328a262e
...
@@ -37,7 +37,7 @@ void main() {
...
@@ -37,7 +37,7 @@ void main() {
expect
(
log
,
equals
(<
dynamic
>[
false
,
'-'
,
false
]));
expect
(
log
,
equals
(<
dynamic
>[
false
,
'-'
,
false
]));
});
});
testWidgets
(
'SwitchListTile
semantics
test'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'SwitchListTile
control
test'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
wrap
(
await
tester
.
pumpWidget
(
wrap
(
child:
Column
(
child:
Column
(
...
...
packages/flutter/test/material/switch_test.dart
View file @
328a262e
...
@@ -301,7 +301,8 @@ void main() {
...
@@ -301,7 +301,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x52000000
),
// Black with 32% opacity
color:
const
Color
(
0x52000000
),
// Black with 32% opacity
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -316,7 +317,8 @@ void main() {
...
@@ -316,7 +317,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
blue
[
600
]!.
withAlpha
(
0x80
),
color:
Colors
.
blue
[
600
]!.
withAlpha
(
0x80
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -349,7 +351,8 @@ void main() {
...
@@ -349,7 +351,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -380,7 +383,8 @@ void main() {
...
@@ -380,7 +383,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -423,7 +427,8 @@ void main() {
...
@@ -423,7 +427,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
blue
[
500
],
color:
Colors
.
blue
[
500
],
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -437,7 +442,8 @@ void main() {
...
@@ -437,7 +442,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
green
[
500
],
color:
Colors
.
green
[
500
],
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -522,19 +528,19 @@ void main() {
...
@@ -522,19 +528,19 @@ void main() {
await
gesture
.
up
();
await
gesture
.
up
();
await
tester
.
pump
();
await
tester
.
pump
();
expect
(
value
,
isFalse
);
expect
(
value
,
isFalse
);
final
ToggleableStateMixin
state
=
tester
.
state
<
ToggleableStateMixin
>(
final
RenderToggleable
renderObject
=
tester
.
renderObject
<
RenderToggleable
>(
find
.
descendant
(
find
.
descendant
(
of:
find
.
byType
(
Switch
),
of:
find
.
byType
(
Switch
),
matching:
find
.
byWidgetPredicate
(
matching:
find
.
byWidgetPredicate
(
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_
MaterialSwitch
'
,
(
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_
SwitchRenderObjectWidget
'
,
),
),
),
),
);
);
expect
(
state
.
position
.
value
,
lessThan
(
0.5
));
expect
(
renderObject
.
position
.
value
,
lessThan
(
0.5
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
value
,
isFalse
);
expect
(
value
,
isFalse
);
expect
(
state
.
position
.
value
,
0
);
expect
(
renderObject
.
position
.
value
,
0
);
// Move past the middle.
// Move past the middle.
gesture
=
await
tester
.
startGesture
(
tester
.
getRect
(
find
.
byType
(
Switch
)).
center
);
gesture
=
await
tester
.
startGesture
(
tester
.
getRect
(
find
.
byType
(
Switch
)).
center
);
...
@@ -543,12 +549,12 @@ void main() {
...
@@ -543,12 +549,12 @@ void main() {
await
gesture
.
up
();
await
gesture
.
up
();
await
tester
.
pump
();
await
tester
.
pump
();
expect
(
value
,
isTrue
);
expect
(
value
,
isTrue
);
expect
(
state
.
position
.
value
,
greaterThan
(
0.5
));
expect
(
renderObject
.
position
.
value
,
greaterThan
(
0.5
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
value
,
isTrue
);
expect
(
value
,
isTrue
);
expect
(
state
.
position
.
value
,
1.0
);
expect
(
renderObject
.
position
.
value
,
1.0
);
// Now move back to the left, the revert animation should play.
// Now move back to the left, the revert animation should play.
gesture
=
await
tester
.
startGesture
(
tester
.
getRect
(
find
.
byType
(
Switch
)).
center
);
gesture
=
await
tester
.
startGesture
(
tester
.
getRect
(
find
.
byType
(
Switch
)).
center
);
...
@@ -557,12 +563,12 @@ void main() {
...
@@ -557,12 +563,12 @@ void main() {
await
gesture
.
up
();
await
gesture
.
up
();
await
tester
.
pump
();
await
tester
.
pump
();
expect
(
value
,
isTrue
);
expect
(
value
,
isTrue
);
expect
(
state
.
position
.
value
,
lessThan
(
0.5
));
expect
(
renderObject
.
position
.
value
,
lessThan
(
0.5
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
value
,
isTrue
);
expect
(
value
,
isTrue
);
expect
(
state
.
position
.
value
,
1.0
);
expect
(
renderObject
.
position
.
value
,
1.0
);
});
});
testWidgets
(
'switch has semantic events'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'switch has semantic events'
,
(
WidgetTester
tester
)
async
{
...
@@ -595,7 +601,7 @@ void main() {
...
@@ -595,7 +601,7 @@ void main() {
),
),
);
);
await
tester
.
tap
(
find
.
byType
(
Switch
));
await
tester
.
tap
(
find
.
byType
(
Switch
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
byType
(
Switch
));
final
RenderObject
object
=
tester
.
firstRenderObject
(
find
.
byType
(
Focus
));
expect
(
value
,
true
);
expect
(
value
,
true
);
expect
(
semanticEvent
,
<
String
,
dynamic
>{
expect
(
semanticEvent
,
<
String
,
dynamic
>{
...
@@ -744,7 +750,8 @@ void main() {
...
@@ -744,7 +750,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x801e88e5
),
color:
const
Color
(
0x801e88e5
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
...
@@ -762,7 +769,8 @@ void main() {
...
@@ -762,7 +769,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x52000000
),
color:
const
Color
(
0x52000000
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
...
@@ -780,7 +788,8 @@ void main() {
...
@@ -780,7 +788,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x1f000000
),
color:
const
Color
(
0x1f000000
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -845,7 +854,8 @@ void main() {
...
@@ -845,7 +854,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x801e88e5
),
color:
const
Color
(
0x801e88e5
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -865,7 +875,8 @@ void main() {
...
@@ -865,7 +875,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x801e88e5
),
color:
const
Color
(
0x801e88e5
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
Colors
.
orange
[
500
])
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
...
@@ -881,7 +892,8 @@ void main() {
...
@@ -881,7 +892,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x1f000000
),
color:
const
Color
(
0x1f000000
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1058,7 +1070,8 @@ void main() {
...
@@ -1058,7 +1070,8 @@ void main() {
),
),
);
);
final
ToggleableStateMixin
oldSwitchState
=
tester
.
state
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_MaterialSwitch'
));
final
RenderToggleable
oldSwitchRenderObject
=
tester
.
renderObject
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
is
LeafRenderObjectWidget
));
stateSetter
(()
{
value
=
false
;
});
stateSetter
(()
{
value
=
false
;
});
await
tester
.
pump
();
await
tester
.
pump
();
...
@@ -1066,12 +1079,14 @@ void main() {
...
@@ -1066,12 +1079,14 @@ void main() {
stateSetter
(()
{
enabled
=
false
;
});
stateSetter
(()
{
enabled
=
false
;
});
await
tester
.
pump
();
await
tester
.
pump
();
final
ToggleableStateMixin
updatedSwitchState
=
tester
.
state
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_MaterialSwitch'
));
final
RenderToggleable
updatedSwitchRenderObject
=
tester
.
renderObject
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
is
LeafRenderObjectWidget
));
expect
(
updatedSwitchState
.
isInteractive
,
false
);
expect
(
updatedSwitchState
,
oldSwitchState
);
expect
(
updatedSwitchRenderObject
.
isInteractive
,
false
);
expect
(
updatedSwitchState
.
position
.
isCompleted
,
false
);
expect
(
updatedSwitchRenderObject
,
oldSwitchRenderObject
);
expect
(
updatedSwitchState
.
position
.
isDismissed
,
false
);
expect
(
updatedSwitchRenderObject
.
position
.
isCompleted
,
false
);
expect
(
updatedSwitchRenderObject
.
position
.
isDismissed
,
false
);
});
});
testWidgets
(
'Switch thumb color resolves in active/enabled states'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Switch thumb color resolves in active/enabled states'
,
(
WidgetTester
tester
)
async
{
...
@@ -1122,7 +1137,8 @@ void main() {
...
@@ -1122,7 +1137,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1138,7 +1154,8 @@ void main() {
...
@@ -1138,7 +1154,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1154,7 +1171,8 @@ void main() {
...
@@ -1154,7 +1171,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x52000000
),
// Black with 32% opacity,
color:
const
Color
(
0x52000000
),
// Black with 32% opacity,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1170,7 +1188,8 @@ void main() {
...
@@ -1170,7 +1188,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1227,7 +1246,8 @@ void main() {
...
@@ -1227,7 +1246,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x801e88e5
),
color:
const
Color
(
0x801e88e5
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
...
@@ -1248,7 +1268,8 @@ void main() {
...
@@ -1248,7 +1268,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
const
Color
(
0x801e88e5
),
color:
const
Color
(
0x801e88e5
),
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
...
@@ -1306,7 +1327,8 @@ void main() {
...
@@ -1306,7 +1327,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
inactiveDisabledTrackColor
,
color:
inactiveDisabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Inactive disabled switch track should use this value'
,
reason:
'Inactive disabled switch track should use this value'
,
);
);
...
@@ -1318,7 +1340,8 @@ void main() {
...
@@ -1318,7 +1340,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
activeDisabledTrackColor
,
color:
activeDisabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Active disabled switch should match these colors'
,
reason:
'Active disabled switch should match these colors'
,
);
);
...
@@ -1330,7 +1353,8 @@ void main() {
...
@@ -1330,7 +1353,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
inactiveEnabledTrackColor
,
color:
inactiveEnabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Inactive enabled switch should match these colors'
,
reason:
'Inactive enabled switch should match these colors'
,
);
);
...
@@ -1342,7 +1366,8 @@ void main() {
...
@@ -1342,7 +1366,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
inactiveDisabledTrackColor
,
color:
inactiveDisabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Inactive disabled switch should match these colors'
,
reason:
'Inactive disabled switch should match these colors'
,
);
);
});
});
...
@@ -1395,7 +1420,8 @@ void main() {
...
@@ -1395,7 +1420,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
focusedTrackColor
,
color:
focusedTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Inactive enabled switch should match these colors'
,
reason:
'Inactive enabled switch should match these colors'
,
);
);
...
@@ -1411,7 +1437,8 @@ void main() {
...
@@ -1411,7 +1437,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
hoveredTrackColor
,
color:
hoveredTrackColor
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
))),
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
))),
reason:
'Inactive enabled switch should match these colors'
,
reason:
'Inactive enabled switch should match these colors'
,
);
);
});
});
...
@@ -1461,7 +1488,8 @@ void main() {
...
@@ -1461,7 +1488,8 @@ void main() {
paints
paints
..
rrect
(
..
rrect
(
color:
Colors
.
black12
,
color:
Colors
.
black12
,
rrect:
RRect
.
fromLTRBR
(
13.0
,
17.0
,
46.0
,
31.0
,
const
Radius
.
circular
(
7.0
)))
rrect:
RRect
.
fromLTRBR
(
383.5
,
293.0
,
416.5
,
307.0
,
const
Radius
.
circular
(
7.0
)))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x33000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x24000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
..
circle
(
color:
const
Color
(
0x1f000000
))
...
@@ -1610,27 +1638,4 @@ void main() {
...
@@ -1610,27 +1638,4 @@ void main() {
reason:
'Hovered Switch should use overlay color
$hoverOverlayColor
over
$hoverColor
'
,
reason:
'Hovered Switch should use overlay color
$hoverOverlayColor
over
$hoverColor
'
,
);
);
});
});
testWidgets
(
'Do not crash when widget disappears while pointer is down'
,
(
WidgetTester
tester
)
async
{
Widget
buildSwitch
(
bool
show
)
{
return
MaterialApp
(
home:
Material
(
child:
Center
(
child:
show
?
Switch
(
value:
true
,
onChanged:
(
_
)
{
})
:
Container
(),
),
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
(
true
));
final
Offset
center
=
tester
.
getCenter
(
find
.
byType
(
Switch
));
// Put a pointer down on the screen.
final
TestGesture
gesture
=
await
tester
.
startGesture
(
center
);
await
tester
.
pump
();
// While the pointer is down, the widget disappears.
await
tester
.
pumpWidget
(
buildSwitch
(
false
));
expect
(
find
.
byType
(
Switch
),
findsNothing
);
// Release pointer after widget disappeared.
gesture
.
up
();
});
}
}
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