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
75fac6ae
Unverified
Commit
75fac6ae
authored
Sep 09, 2022
by
Qun Cheng
Committed by
GitHub
Sep 09, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrated `Switch` to Material 3 (#110095)
parent
e3f8ee88
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
2287 additions
and
340 deletions
+2287
-340
gen_defaults.dart
dev/tools/gen_defaults/bin/gen_defaults.dart
+2
-0
switch_template.dart
dev/tools/gen_defaults/lib/switch_template.dart
+208
-0
switch.2.dart
examples/api/lib/material/switch/switch.2.dart
+74
-0
switch.dart
packages/flutter/lib/src/material/switch.dart
+677
-94
switch_theme.dart
packages/flutter/lib/src/material/switch_theme.dart
+13
-1
theme_data.dart
packages/flutter/lib/src/material/theme_data.dart
+2
-1
switch_test.dart
packages/flutter/test/material/switch_test.dart
+1125
-137
switch_theme_test.dart
packages/flutter/test/material/switch_theme_test.dart
+186
-107
No files found.
dev/tools/gen_defaults/bin/gen_defaults.dart
View file @
75fac6ae
...
@@ -31,6 +31,7 @@ import 'package:gen_defaults/input_decorator_template.dart';
...
@@ -31,6 +31,7 @@ import 'package:gen_defaults/input_decorator_template.dart';
import
'package:gen_defaults/navigation_bar_template.dart'
;
import
'package:gen_defaults/navigation_bar_template.dart'
;
import
'package:gen_defaults/navigation_rail_template.dart'
;
import
'package:gen_defaults/navigation_rail_template.dart'
;
import
'package:gen_defaults/surface_tint.dart'
;
import
'package:gen_defaults/surface_tint.dart'
;
import
'package:gen_defaults/switch_template.dart'
;
import
'package:gen_defaults/text_field_template.dart'
;
import
'package:gen_defaults/text_field_template.dart'
;
import
'package:gen_defaults/typography_template.dart'
;
import
'package:gen_defaults/typography_template.dart'
;
...
@@ -121,6 +122,7 @@ Future<void> main(List<String> args) async {
...
@@ -121,6 +122,7 @@ Future<void> main(List<String> args) async {
NavigationBarTemplate
(
'NavigationBar'
,
'
$materialLib
/navigation_bar.dart'
,
tokens
).
updateFile
();
NavigationBarTemplate
(
'NavigationBar'
,
'
$materialLib
/navigation_bar.dart'
,
tokens
).
updateFile
();
NavigationRailTemplate
(
'NavigationRail'
,
'
$materialLib
/navigation_rail.dart'
,
tokens
).
updateFile
();
NavigationRailTemplate
(
'NavigationRail'
,
'
$materialLib
/navigation_rail.dart'
,
tokens
).
updateFile
();
SurfaceTintTemplate
(
'SurfaceTint'
,
'
$materialLib
/elevation_overlay.dart'
,
tokens
).
updateFile
();
SurfaceTintTemplate
(
'SurfaceTint'
,
'
$materialLib
/elevation_overlay.dart'
,
tokens
).
updateFile
();
SwitchTemplate
(
'Switch'
,
'
$materialLib
/switch.dart'
,
tokens
).
updateFile
();
TextFieldTemplate
(
'TextField'
,
'
$materialLib
/text_field.dart'
,
tokens
).
updateFile
();
TextFieldTemplate
(
'TextField'
,
'
$materialLib
/text_field.dart'
,
tokens
).
updateFile
();
TypographyTemplate
(
'Typography'
,
'
$materialLib
/typography.dart'
,
tokens
).
updateFile
();
TypographyTemplate
(
'Typography'
,
'
$materialLib
/typography.dart'
,
tokens
).
updateFile
();
}
}
dev/tools/gen_defaults/lib/switch_template.dart
0 → 100644
View file @
75fac6ae
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'template.dart'
;
class
SwitchTemplate
extends
TokenTemplate
{
const
SwitchTemplate
(
super
.
blockName
,
super
.
fileName
,
super
.
tokens
,
{
super
.
colorSchemePrefix
=
'_colors.'
,
});
@override
String
generate
()
=>
'''
class _
${blockName}
DefaultsM3 extends SwitchThemeData {
_
${blockName}
DefaultsM3(BuildContext context)
: _colors = Theme.of(context).colorScheme;
final ColorScheme _colors;
@override
MaterialStateProperty<Color> get thumbColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return
${componentColor('md.comp.switch.disabled.selected.handle')}
;
}
return
${componentColor('md.comp.switch.disabled.unselected.handle')}
;
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.selected.pressed.handle')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.selected.hover.handle')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.selected.focus.handle')}
;
}
return
${componentColor('md.comp.switch.selected.handle')}
;
}
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.unselected.pressed.handle')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.unselected.hover.handle')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.unselected.focus.handle')}
;
}
return
${componentColor('md.comp.switch.unselected.handle')}
;
});
}
@override
MaterialStateProperty<Color> get trackColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return
${componentColor('md.comp.switch.disabled.selected.track')}
.withOpacity(
${opacity('md.comp.switch.disabled.track.opacity')}
);
}
return
${componentColor('md.comp.switch.disabled.unselected.track')}
.withOpacity(
${opacity('md.comp.switch.disabled.track.opacity')}
);
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.selected.pressed.track')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.selected.hover.track')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.selected.focus.track')}
;
}
return
${componentColor('md.comp.switch.selected.track')}
;
}
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.unselected.pressed.track')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.unselected.hover.track')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.unselected.focus.track')}
;
}
return
${componentColor('md.comp.switch.unselected.track')}
;
});
}
@override
MaterialStateProperty<Color?> get overlayColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.selected.pressed.state-layer')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.selected.hover.state-layer')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.selected.focus.state-layer')}
;
}
return null;
}
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.unselected.pressed.state-layer')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.unselected.hover.state-layer')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.unselected.focus.state-layer')}
;
}
return null;
});
}
@override
double get splashRadius =>
${tokens['md.comp.switch.state-layer.size']}
/ 2;
}
class _SwitchConfigM3 with _SwitchConfig {
_SwitchConfigM3(this.context)
: _colors = Theme.of(context).colorScheme;
BuildContext context;
final ColorScheme _colors;
static const double iconSize =
${tokens['md.comp.switch.unselected.icon.size']}
;
@override
double get activeThumbRadius =>
${tokens['md.comp.switch.selected.handle.width']}
/ 2;
@override
MaterialStateProperty<Color> get iconColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return
${componentColor('md.comp.switch.disabled.selected.icon')}
;
}
return
${componentColor('md.comp.switch.disabled.unselected.icon')}
;
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.selected.pressed.icon')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.selected.hover.icon')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.selected.focus.icon')}
;
}
return
${componentColor('md.comp.switch.selected.icon')}
;
}
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.switch.unselected.pressed.icon')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.switch.unselected.hover.icon')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.switch.unselected.focus.icon')}
;
}
return
${componentColor('md.comp.switch.unselected.icon')}
;
});
}
@override
double get inactiveThumbRadius =>
${tokens['md.comp.switch.unselected.handle.width']}
/ 2;
@override
double get pressedThumbRadius =>
${tokens['md.comp.switch.pressed.handle.width']}
/ 2;
@override
double get switchHeight => _kSwitchMinSize + 8.0;
@override
double get switchHeightCollapsed => _kSwitchMinSize;
@override
double get switchWidth => trackWidth - 2 * (trackHeight / 2.0) + _kSwitchMinSize;
@override
double get thumbRadiusWithIcon =>
${tokens['md.comp.switch.with-icon.handle.width']}
/ 2;
@override
List<BoxShadow>? get thumbShadow => kElevationToShadow[0];
@override
double get trackHeight =>
${tokens['md.comp.switch.track.height']}
;
@override
MaterialStateProperty<Color?> get trackOutlineColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return null;
}
if (states.contains(MaterialState.disabled)) {
return
${componentColor('md.comp.switch.disabled.unselected.track.outline')}
.withOpacity(
${opacity('md.comp.switch.disabled.track.opacity')}
);
}
return
${componentColor('md.comp.switch.unselected.track.outline')}
;
});
}
@override
double get trackWidth =>
${tokens['md.comp.switch.track.width']}
;
}
'''
;
}
examples/api/lib/material/switch/switch.2.dart
0 → 100644
View file @
75fac6ae
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flutter code sample for Switch
import
'package:flutter/material.dart'
;
void
main
(
)
=>
runApp
(
const
SwitchApp
());
class
SwitchApp
extends
StatelessWidget
{
const
SwitchApp
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
MaterialApp
(
theme:
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
)),
home:
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
'Switch Sample'
)),
body:
const
Center
(
child:
SwitchExample
(),
),
),
);
}
}
class
SwitchExample
extends
StatefulWidget
{
const
SwitchExample
({
super
.
key
});
@override
State
<
SwitchExample
>
createState
()
=>
_SwitchExampleState
();
}
class
_SwitchExampleState
extends
State
<
SwitchExample
>
{
bool
light0
=
true
;
bool
light1
=
true
;
bool
light2
=
true
;
final
MaterialStateProperty
<
Icon
?>
thumbIcon
=
MaterialStateProperty
.
resolveWith
<
Icon
?>((
Set
<
MaterialState
>
states
)
{
// Thumb icon when the switch is selected.
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
const
Icon
(
Icons
.
check
);
}
return
const
Icon
(
Icons
.
close
);
},
);
@override
Widget
build
(
BuildContext
context
)
{
return
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
Switch
(
value:
light0
,
onChanged:
(
bool
value
)
{
setState
(()
{
light0
=
value
;
});
},
),
Switch
(
thumbIcon:
thumbIcon
,
value:
light1
,
onChanged:
(
bool
value
)
{
setState
(()
{
light1
=
value
;
});
},
),
],
);
}
}
packages/flutter/lib/src/material/switch.dart
View file @
75fac6ae
...
@@ -2,11 +2,14 @@
...
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:ui'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/cupertino.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
'color_scheme.dart'
;
import
'colors.dart'
;
import
'colors.dart'
;
import
'constants.dart'
;
import
'constants.dart'
;
import
'debug.dart'
;
import
'debug.dart'
;
...
@@ -21,14 +24,7 @@ import 'toggleable.dart';
...
@@ -21,14 +24,7 @@ import 'toggleable.dart';
// bool _giveVerse = true;
// bool _giveVerse = true;
// late StateSetter setState;
// late StateSetter setState;
const
double
_kTrackHeight
=
14.0
;
const
double
_kTrackWidth
=
33.0
;
const
double
_kTrackRadius
=
_kTrackHeight
/
2.0
;
const
double
_kThumbRadius
=
10.0
;
const
double
_kSwitchMinSize
=
kMinInteractiveDimension
-
8.0
;
const
double
_kSwitchMinSize
=
kMinInteractiveDimension
-
8.0
;
const
double
_kSwitchWidth
=
_kTrackWidth
-
2
*
_kTrackRadius
+
_kSwitchMinSize
;
const
double
_kSwitchHeight
=
_kSwitchMinSize
+
8.0
;
const
double
_kSwitchHeightCollapsed
=
_kSwitchMinSize
;
enum
_SwitchType
{
material
,
adaptive
}
enum
_SwitchType
{
material
,
adaptive
}
...
@@ -48,6 +44,10 @@ enum _SwitchType { material, adaptive }
...
@@ -48,6 +44,10 @@ enum _SwitchType { material, adaptive }
///
///
/// Requires one of its ancestors to be a [Material] widget.
/// Requires one of its ancestors to be a [Material] widget.
///
///
/// Material Design 3 provides the option to add icons on the thumb of the [Switch].
/// If [ThemeData.useMaterial3] is set to true, users can use [Switch.thumbIcon]
/// to add optional Icons based on the different [MaterialState]s of the [Switch].
///
/// {@tool dartpad}
/// {@tool dartpad}
/// This example shows a toggleable [Switch]. When the thumb slides to the other
/// This example shows a toggleable [Switch]. When the thumb slides to the other
/// side of the track, the switch is toggled between on/off.
/// side of the track, the switch is toggled between on/off.
...
@@ -62,6 +62,13 @@ enum _SwitchType { material, adaptive }
...
@@ -62,6 +62,13 @@ enum _SwitchType { material, adaptive }
/// ** See code in examples/api/lib/material/switch/switch.1.dart **
/// ** See code in examples/api/lib/material/switch/switch.1.dart **
/// {@end-tool}
/// {@end-tool}
///
///
/// {@tool dartpad}
/// This example shows how to add icons on the thumb of the [Switch] using the
/// [Switch.thumbIcon] property.
///
/// ** See code in examples/api/lib/material/switch/switch.2.dart **
/// {@end-tool}
///
/// See also:
/// See also:
///
///
/// * [SwitchListTile], which combines this widget with a [ListTile] so that
/// * [SwitchListTile], which combines this widget with a [ListTile] so that
...
@@ -98,6 +105,7 @@ class Switch extends StatelessWidget {
...
@@ -98,6 +105,7 @@ class Switch extends StatelessWidget {
this
.
onInactiveThumbImageError
,
this
.
onInactiveThumbImageError
,
this
.
thumbColor
,
this
.
thumbColor
,
this
.
trackColor
,
this
.
trackColor
,
this
.
thumbIcon
,
this
.
materialTapTargetSize
,
this
.
materialTapTargetSize
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
mouseCursor
,
this
.
mouseCursor
,
...
@@ -142,6 +150,7 @@ class Switch extends StatelessWidget {
...
@@ -142,6 +150,7 @@ class Switch extends StatelessWidget {
this
.
materialTapTargetSize
,
this
.
materialTapTargetSize
,
this
.
thumbColor
,
this
.
thumbColor
,
this
.
trackColor
,
this
.
trackColor
,
this
.
thumbIcon
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
mouseCursor
,
this
.
mouseCursor
,
this
.
focusColor
,
this
.
focusColor
,
...
@@ -322,6 +331,39 @@ class Switch extends StatelessWidget {
...
@@ -322,6 +331,39 @@ class Switch extends StatelessWidget {
/// | Disabled | `Colors.black12` | `Colors.white10` |
/// | Disabled | `Colors.black12` | `Colors.white10` |
final
MaterialStateProperty
<
Color
?>?
trackColor
;
final
MaterialStateProperty
<
Color
?>?
trackColor
;
/// {@template flutter.material.switch.thumbIcon}
/// The icon to use on the thumb of this switch
///
/// Resolved in the following states:
/// * [MaterialState.selected].
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
///
/// {@tool snippet}
/// This example resolves the [thumbIcon] based on the current
/// [MaterialState] of the [Switch], providing a different [Icon] when it is
/// [MaterialState.disabled].
///
/// ```dart
/// Switch(
/// value: true,
/// onChanged: (_) => true,
/// thumbIcon: MaterialStateProperty.resolveWith<Icon?>((Set<MaterialState> states) {
/// if (states.contains(MaterialState.disabled)) {
/// return const Icon(Icons.close);
/// }
/// return null; // All other states will use the default thumbIcon.
/// }),
/// )
/// ```
/// {@end-tool}
/// {@endtemplate}
///
/// If null, then the value of [SwitchThemeData.thumbIcon] is used. If this is also null,
/// then the [Switch] does not have any icons on the thumb.
final
MaterialStateProperty
<
Icon
?>?
thumbIcon
;
/// {@template flutter.material.switch.materialTapTargetSize}
/// {@template flutter.material.switch.materialTapTargetSize}
/// Configures the minimum size of the tap target.
/// Configures the minimum size of the tap target.
/// {@endtemplate}
/// {@endtemplate}
...
@@ -419,15 +461,16 @@ class Switch extends StatelessWidget {
...
@@ -419,15 +461,16 @@ class Switch extends StatelessWidget {
Size
_getSwitchSize
(
BuildContext
context
)
{
Size
_getSwitchSize
(
BuildContext
context
)
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
SwitchThemeData
switchTheme
=
SwitchTheme
.
of
(
context
);
final
SwitchThemeData
switchTheme
=
SwitchTheme
.
of
(
context
);
final
_SwitchConfig
switchConfig
=
theme
.
useMaterial3
?
_SwitchConfigM3
(
context
)
:
_SwitchConfigM2
();
final
MaterialTapTargetSize
effectiveMaterialTapTargetSize
=
materialTapTargetSize
final
MaterialTapTargetSize
effectiveMaterialTapTargetSize
=
materialTapTargetSize
??
switchTheme
.
materialTapTargetSize
??
switchTheme
.
materialTapTargetSize
??
theme
.
materialTapTargetSize
;
??
theme
.
materialTapTargetSize
;
switch
(
effectiveMaterialTapTargetSize
)
{
switch
(
effectiveMaterialTapTargetSize
)
{
case
MaterialTapTargetSize
.
padded
:
case
MaterialTapTargetSize
.
padded
:
return
const
Size
(
_kSwitchWidth
,
_kS
witchHeight
);
return
Size
(
switchConfig
.
switchWidth
,
switchConfig
.
s
witchHeight
);
case
MaterialTapTargetSize
.
shrinkWrap
:
case
MaterialTapTargetSize
.
shrinkWrap
:
return
const
Size
(
_kSwitchWidth
,
_kS
witchHeightCollapsed
);
return
Size
(
switchConfig
.
switchWidth
,
switchConfig
.
s
witchHeightCollapsed
);
}
}
}
}
...
@@ -466,6 +509,7 @@ class Switch extends StatelessWidget {
...
@@ -466,6 +509,7 @@ class Switch extends StatelessWidget {
onInactiveThumbImageError:
onInactiveThumbImageError
,
onInactiveThumbImageError:
onInactiveThumbImageError
,
thumbColor:
thumbColor
,
thumbColor:
thumbColor
,
trackColor:
trackColor
,
trackColor:
trackColor
,
thumbIcon:
thumbIcon
,
materialTapTargetSize:
materialTapTargetSize
,
materialTapTargetSize:
materialTapTargetSize
,
dragStartBehavior:
dragStartBehavior
,
dragStartBehavior:
dragStartBehavior
,
mouseCursor:
mouseCursor
,
mouseCursor:
mouseCursor
,
...
@@ -524,6 +568,7 @@ class _MaterialSwitch extends StatefulWidget {
...
@@ -524,6 +568,7 @@ class _MaterialSwitch extends StatefulWidget {
this
.
onInactiveThumbImageError
,
this
.
onInactiveThumbImageError
,
this
.
thumbColor
,
this
.
thumbColor
,
this
.
trackColor
,
this
.
trackColor
,
this
.
thumbIcon
,
this
.
materialTapTargetSize
,
this
.
materialTapTargetSize
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
mouseCursor
,
this
.
mouseCursor
,
...
@@ -549,6 +594,7 @@ class _MaterialSwitch extends StatefulWidget {
...
@@ -549,6 +594,7 @@ class _MaterialSwitch extends StatefulWidget {
final
ImageErrorListener
?
onInactiveThumbImageError
;
final
ImageErrorListener
?
onInactiveThumbImageError
;
final
MaterialStateProperty
<
Color
?>?
thumbColor
;
final
MaterialStateProperty
<
Color
?>?
thumbColor
;
final
MaterialStateProperty
<
Color
?>?
trackColor
;
final
MaterialStateProperty
<
Color
?>?
trackColor
;
final
MaterialStateProperty
<
Icon
?>?
thumbIcon
;
final
MaterialTapTargetSize
?
materialTapTargetSize
;
final
MaterialTapTargetSize
?
materialTapTargetSize
;
final
DragStartBehavior
dragStartBehavior
;
final
DragStartBehavior
dragStartBehavior
;
final
MouseCursor
?
mouseCursor
;
final
MouseCursor
?
mouseCursor
;
...
@@ -609,26 +655,8 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -609,26 +655,8 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
});
});
}
}
MaterialStateProperty
<
Color
>
get
_defaultThumbColor
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
bool
isDark
=
theme
.
brightness
==
Brightness
.
dark
;
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
isDark
?
Colors
.
grey
.
shade800
:
Colors
.
grey
.
shade400
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
theme
.
colorScheme
.
secondary
;
}
return
isDark
?
Colors
.
grey
.
shade400
:
Colors
.
grey
.
shade50
;
});
}
MaterialStateProperty
<
Color
?>
get
_widgetTrackColor
{
MaterialStateProperty
<
Color
?>
get
_widgetTrackColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
widget
.
inactiveTrackColor
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
widget
.
activeTrackColor
;
return
widget
.
activeTrackColor
;
}
}
...
@@ -636,28 +664,15 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -636,28 +664,15 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
});
});
}
}
MaterialStateProperty
<
Color
>
get
_defaultTrackColor
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
bool
isDark
=
theme
.
brightness
==
Brightness
.
dark
;
const
Color
black32
=
Color
(
0x52000000
);
// Black with 32% opacity
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
isDark
?
Colors
.
white10
:
Colors
.
black12
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
final
Set
<
MaterialState
>
activeState
=
states
..
add
(
MaterialState
.
selected
);
final
Color
activeColor
=
_widgetThumbColor
.
resolve
(
activeState
)
??
_defaultThumbColor
.
resolve
(
activeState
);
return
activeColor
.
withAlpha
(
0x80
);
}
return
isDark
?
Colors
.
white30
:
black32
;
});
}
double
get
_trackInnerLength
=>
widget
.
size
.
width
-
_kSwitchMinSize
;
double
get
_trackInnerLength
=>
widget
.
size
.
width
-
_kSwitchMinSize
;
bool
_isPressed
=
false
;
void
_handleDragStart
(
DragStartDetails
details
)
{
void
_handleDragStart
(
DragStartDetails
details
)
{
if
(
isInteractive
)
{
if
(
isInteractive
)
{
setState
(()
{
_isPressed
=
true
;
});
reactionController
.
forward
();
reactionController
.
forward
();
}
}
}
}
...
@@ -692,6 +707,9 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -692,6 +707,9 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
}
else
{
}
else
{
animateToValue
();
animateToValue
();
}
}
setState
(()
{
_isPressed
=
false
;
});
reactionController
.
reverse
();
reactionController
.
reverse
();
}
}
...
@@ -713,49 +731,66 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -713,49 +731,66 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
SwitchThemeData
switchTheme
=
SwitchTheme
.
of
(
context
);
final
SwitchThemeData
switchTheme
=
SwitchTheme
.
of
(
context
);
final
_SwitchConfig
switchConfig
=
theme
.
useMaterial3
?
_SwitchConfigM3
(
context
)
:
_SwitchConfigM2
();
final
SwitchThemeData
defaults
=
theme
.
useMaterial3
?
_SwitchDefaultsM3
(
context
)
:
_SwitchDefaultsM2
(
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
?
activeThumbColor
=
widget
.
thumbColor
?.
resolve
(
activeStates
)
??
_widgetThumbColor
.
resolve
(
activeStates
)
??
_widgetThumbColor
.
resolve
(
activeStates
)
??
switchTheme
.
thumbColor
?.
resolve
(
activeStates
)
??
switchTheme
.
thumbColor
?.
resolve
(
activeStates
);
??
_defaultThumbColor
.
resolve
(
activeStates
);
final
Color
effectiveActiveThumbColor
=
activeThumbColor
final
Color
effectiveInactiveThumbColor
=
widget
.
thumbColor
?.
resolve
(
inactiveStates
)
??
defaults
.
thumbColor
!.
resolve
(
activeStates
)!;
final
Color
?
inactiveThumbColor
=
widget
.
thumbColor
?.
resolve
(
inactiveStates
)
??
_widgetThumbColor
.
resolve
(
inactiveStates
)
??
_widgetThumbColor
.
resolve
(
inactiveStates
)
??
switchTheme
.
thumbColor
?.
resolve
(
inactiveStates
)
??
switchTheme
.
thumbColor
?.
resolve
(
inactiveStates
);
??
_defaultThumbColor
.
resolve
(
inactiveStates
);
final
Color
effectiveInactiveThumbColor
=
inactiveThumbColor
??
defaults
.
thumbColor
!.
resolve
(
inactiveStates
)!;
final
Color
effectiveActiveTrackColor
=
widget
.
trackColor
?.
resolve
(
activeStates
)
final
Color
effectiveActiveTrackColor
=
widget
.
trackColor
?.
resolve
(
activeStates
)
??
_widgetTrackColor
.
resolve
(
activeStates
)
??
_widgetTrackColor
.
resolve
(
activeStates
)
??
switchTheme
.
trackColor
?.
resolve
(
activeStates
)
??
switchTheme
.
trackColor
?.
resolve
(
activeStates
)
??
_defaultTrackColor
.
resolve
(
activeStates
);
??
_widgetThumbColor
.
resolve
(
activeStates
)?.
withAlpha
(
0x80
)
??
defaults
.
trackColor
!.
resolve
(
activeStates
)!;
final
Color
effectiveInactiveTrackColor
=
widget
.
trackColor
?.
resolve
(
inactiveStates
)
final
Color
effectiveInactiveTrackColor
=
widget
.
trackColor
?.
resolve
(
inactiveStates
)
??
_widgetTrackColor
.
resolve
(
inactiveStates
)
??
_widgetTrackColor
.
resolve
(
inactiveStates
)
??
switchTheme
.
trackColor
?.
resolve
(
inactiveStates
)
??
switchTheme
.
trackColor
?.
resolve
(
inactiveStates
)
??
_defaultTrackColor
.
resolve
(
inactiveStates
);
??
defaults
.
trackColor
!.
resolve
(
inactiveStates
)!;
final
Color
?
effectiveInactiveTrackOutlineColor
=
switchConfig
.
trackOutlineColor
?.
resolve
(
inactiveStates
);
final
Icon
?
effectiveActiveIcon
=
widget
.
thumbIcon
?.
resolve
(
activeStates
)
??
switchTheme
.
thumbIcon
?.
resolve
(
activeStates
);
final
Icon
?
effectiveInactiveIcon
=
widget
.
thumbIcon
?.
resolve
(
inactiveStates
)
??
switchTheme
.
thumbIcon
?.
resolve
(
inactiveStates
);
final
Color
effectiveActiveIconColor
=
effectiveActiveIcon
?.
color
??
switchConfig
.
iconColor
.
resolve
(
activeStates
);
final
Color
effectiveInactiveIconColor
=
effectiveInactiveIcon
?.
color
??
switchConfig
.
iconColor
.
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
??
switchTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
theme
.
focusColor
;
??
defaults
.
overlayColor
!.
resolve
(
focusedStates
)!
;
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
??
switchTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
theme
.
hoverColor
;
??
defaults
.
overlayColor
!.
resolve
(
hoveredStates
)!
;
final
Set
<
MaterialState
>
activePressedStates
=
activeStates
..
add
(
MaterialState
.
pressed
);
final
Set
<
MaterialState
>
activePressedStates
=
activeStates
..
add
(
MaterialState
.
pressed
);
final
Color
effectiveActivePressedOverlayColor
=
widget
.
overlayColor
?.
resolve
(
activePressedStates
)
final
Color
effectiveActivePressedOverlayColor
=
widget
.
overlayColor
?.
resolve
(
activePressedStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
activePressedStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
activePressedStates
)
??
effectiveActiveThumbColor
.
withAlpha
(
kRadialReactionAlpha
);
??
activeThumbColor
?.
withAlpha
(
kRadialReactionAlpha
)
??
defaults
.
overlayColor
!.
resolve
(
activePressedStates
)!;
final
Set
<
MaterialState
>
inactivePressedStates
=
inactiveStates
..
add
(
MaterialState
.
pressed
);
final
Set
<
MaterialState
>
inactivePressedStates
=
inactiveStates
..
add
(
MaterialState
.
pressed
);
final
Color
effectiveInactivePressedOverlayColor
=
widget
.
overlayColor
?.
resolve
(
inactivePressedStates
)
final
Color
effectiveInactivePressedOverlayColor
=
widget
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
switchTheme
.
overlayColor
?.
resolve
(
inactivePressedStates
)
??
effectiveInactiveThumbColor
.
withAlpha
(
kRadialReactionAlpha
);
??
inactiveThumbColor
?.
withAlpha
(
kRadialReactionAlpha
)
??
defaults
.
overlayColor
!.
resolve
(
inactivePressedStates
)!;
final
MaterialStateProperty
<
MouseCursor
>
effectiveMouseCursor
=
MaterialStateProperty
.
resolveWith
<
MouseCursor
>((
Set
<
MaterialState
>
states
)
{
final
MaterialStateProperty
<
MouseCursor
>
effectiveMouseCursor
=
MaterialStateProperty
.
resolveWith
<
MouseCursor
>((
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
states
)
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widget
.
mouseCursor
,
states
)
...
@@ -763,6 +798,11 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -763,6 +798,11 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
states
);
??
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
MaterialStateMouseCursor
.
clickable
,
states
);
});
});
final
double
effectiveActiveThumbRadius
=
effectiveActiveIcon
==
null
?
switchConfig
.
activeThumbRadius
:
switchConfig
.
thumbRadiusWithIcon
;
final
double
effectiveInactiveThumbRadius
=
effectiveInactiveIcon
==
null
&&
widget
.
inactiveThumbImage
==
null
?
switchConfig
.
inactiveThumbRadius
:
switchConfig
.
thumbRadiusWithIcon
;
final
double
effectiveSplashRadius
=
widget
.
splashRadius
??
switchTheme
.
splashRadius
??
defaults
.
splashRadius
!;
return
Semantics
(
return
Semantics
(
toggled:
widget
.
value
,
toggled:
widget
.
value
,
child:
GestureDetector
(
child:
GestureDetector
(
...
@@ -785,10 +825,11 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -785,10 +825,11 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
..
reactionColor
=
effectiveActivePressedOverlayColor
..
reactionColor
=
effectiveActivePressedOverlayColor
..
hoverColor
=
effectiveHoverOverlayColor
..
hoverColor
=
effectiveHoverOverlayColor
..
focusColor
=
effectiveFocusOverlayColor
..
focusColor
=
effectiveFocusOverlayColor
..
splashRadius
=
widget
.
splashRadius
??
switchTheme
.
splashRadius
??
kRadialReaction
Radius
..
splashRadius
=
effectiveSplash
Radius
..
downPosition
=
downPosition
..
downPosition
=
downPosition
..
isFocused
=
states
.
contains
(
MaterialState
.
focused
)
..
isFocused
=
states
.
contains
(
MaterialState
.
focused
)
..
isHovered
=
states
.
contains
(
MaterialState
.
hovered
)
..
isHovered
=
states
.
contains
(
MaterialState
.
hovered
)
..
isPressed
=
_isPressed
||
downPosition
!=
null
..
activeColor
=
effectiveActiveThumbColor
..
activeColor
=
effectiveActiveThumbColor
..
inactiveColor
=
effectiveInactiveThumbColor
..
inactiveColor
=
effectiveInactiveThumbColor
..
activeThumbImage
=
widget
.
activeThumbImage
..
activeThumbImage
=
widget
.
activeThumbImage
...
@@ -797,11 +838,23 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -797,11 +838,23 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
..
onInactiveThumbImageError
=
widget
.
onInactiveThumbImageError
..
onInactiveThumbImageError
=
widget
.
onInactiveThumbImageError
..
activeTrackColor
=
effectiveActiveTrackColor
..
activeTrackColor
=
effectiveActiveTrackColor
..
inactiveTrackColor
=
effectiveInactiveTrackColor
..
inactiveTrackColor
=
effectiveInactiveTrackColor
..
inactiveTrackOutlineColor
=
effectiveInactiveTrackOutlineColor
..
configuration
=
createLocalImageConfiguration
(
context
)
..
configuration
=
createLocalImageConfiguration
(
context
)
..
isInteractive
=
isInteractive
..
isInteractive
=
isInteractive
..
trackInnerLength
=
_trackInnerLength
..
trackInnerLength
=
_trackInnerLength
..
textDirection
=
Directionality
.
of
(
context
)
..
textDirection
=
Directionality
.
of
(
context
)
..
surfaceColor
=
theme
.
colorScheme
.
surface
,
..
surfaceColor
=
theme
.
colorScheme
.
surface
..
inactiveThumbRadius
=
effectiveInactiveThumbRadius
..
activeThumbRadius
=
effectiveActiveThumbRadius
..
pressedThumbRadius
=
switchConfig
.
pressedThumbRadius
..
trackHeight
=
switchConfig
.
trackHeight
..
trackWidth
=
switchConfig
.
trackWidth
..
activeIconColor
=
effectiveActiveIconColor
..
inactiveIconColor
=
effectiveInactiveIconColor
..
activeIcon
=
effectiveActiveIcon
..
inactiveIcon
=
effectiveInactiveIcon
..
iconTheme
=
IconTheme
.
of
(
context
)
..
thumbShadow
=
switchConfig
.
thumbShadow
,
),
),
),
),
);
);
...
@@ -809,6 +862,123 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
...
@@ -809,6 +862,123 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
}
}
class
_SwitchPainter
extends
ToggleablePainter
{
class
_SwitchPainter
extends
ToggleablePainter
{
Icon
?
get
activeIcon
=>
_activeIcon
;
Icon
?
_activeIcon
;
set
activeIcon
(
Icon
?
value
)
{
if
(
value
==
_activeIcon
)
{
return
;
}
_activeIcon
=
value
;
notifyListeners
();
}
Icon
?
get
inactiveIcon
=>
_inactiveIcon
;
Icon
?
_inactiveIcon
;
set
inactiveIcon
(
Icon
?
value
)
{
if
(
value
==
_inactiveIcon
)
{
return
;
}
_inactiveIcon
=
value
;
notifyListeners
();
}
IconThemeData
?
get
iconTheme
=>
_iconTheme
;
IconThemeData
?
_iconTheme
;
set
iconTheme
(
IconThemeData
?
value
)
{
if
(
value
==
_iconTheme
)
{
return
;
}
_iconTheme
=
value
;
notifyListeners
();
}
Color
get
activeIconColor
=>
_activeIconColor
!;
Color
?
_activeIconColor
;
set
activeIconColor
(
Color
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_activeIconColor
)
{
return
;
}
_activeIconColor
=
value
;
notifyListeners
();
}
Color
get
inactiveIconColor
=>
_inactiveIconColor
!;
Color
?
_inactiveIconColor
;
set
inactiveIconColor
(
Color
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_inactiveIconColor
)
{
return
;
}
_inactiveIconColor
=
value
;
notifyListeners
();
}
bool
get
isPressed
=>
_isPressed
!;
bool
?
_isPressed
;
set
isPressed
(
bool
?
value
)
{
if
(
value
==
_isPressed
)
{
return
;
}
_isPressed
=
value
;
notifyListeners
();
}
double
get
activeThumbRadius
=>
_activeThumbRadius
!;
double
?
_activeThumbRadius
;
set
activeThumbRadius
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_activeThumbRadius
)
{
return
;
}
_activeThumbRadius
=
value
;
notifyListeners
();
}
double
get
inactiveThumbRadius
=>
_inactiveThumbRadius
!;
double
?
_inactiveThumbRadius
;
set
inactiveThumbRadius
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_inactiveThumbRadius
)
{
return
;
}
_inactiveThumbRadius
=
value
;
notifyListeners
();
}
double
get
pressedThumbRadius
=>
_pressedThumbRadius
!;
double
?
_pressedThumbRadius
;
set
pressedThumbRadius
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_pressedThumbRadius
)
{
return
;
}
_pressedThumbRadius
=
value
;
notifyListeners
();
}
double
get
trackHeight
=>
_trackHeight
!;
double
?
_trackHeight
;
set
trackHeight
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_trackHeight
)
{
return
;
}
_trackHeight
=
value
;
notifyListeners
();
}
double
get
trackWidth
=>
_trackWidth
!;
double
?
_trackWidth
;
set
trackWidth
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_trackWidth
)
{
return
;
}
_trackWidth
=
value
;
notifyListeners
();
}
ImageProvider
?
get
activeThumbImage
=>
_activeThumbImage
;
ImageProvider
?
get
activeThumbImage
=>
_activeThumbImage
;
ImageProvider
?
_activeThumbImage
;
ImageProvider
?
_activeThumbImage
;
set
activeThumbImage
(
ImageProvider
?
value
)
{
set
activeThumbImage
(
ImageProvider
?
value
)
{
...
@@ -860,6 +1030,16 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -860,6 +1030,16 @@ class _SwitchPainter extends ToggleablePainter {
notifyListeners
();
notifyListeners
();
}
}
Color
?
get
inactiveTrackOutlineColor
=>
_inactiveTrackOutlineColor
;
Color
?
_inactiveTrackOutlineColor
;
set
inactiveTrackOutlineColor
(
Color
?
value
)
{
if
(
value
==
_inactiveTrackOutlineColor
)
{
return
;
}
_inactiveTrackOutlineColor
=
value
;
notifyListeners
();
}
Color
get
inactiveTrackColor
=>
_inactiveTrackColor
!;
Color
get
inactiveTrackColor
=>
_inactiveTrackColor
!;
Color
?
_inactiveTrackColor
;
Color
?
_inactiveTrackColor
;
set
inactiveTrackColor
(
Color
value
)
{
set
inactiveTrackColor
(
Color
value
)
{
...
@@ -924,6 +1104,16 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -924,6 +1104,16 @@ class _SwitchPainter extends ToggleablePainter {
notifyListeners
();
notifyListeners
();
}
}
List
<
BoxShadow
>?
get
thumbShadow
=>
_thumbShadow
;
List
<
BoxShadow
>?
_thumbShadow
;
set
thumbShadow
(
List
<
BoxShadow
>?
value
)
{
if
(
value
==
_thumbShadow
)
{
return
;
}
_thumbShadow
=
value
;
notifyListeners
();
}
Color
?
_cachedThumbColor
;
Color
?
_cachedThumbColor
;
ImageProvider
?
_cachedThumbImage
;
ImageProvider
?
_cachedThumbImage
;
ImageErrorListener
?
_cachedThumbErrorListener
;
ImageErrorListener
?
_cachedThumbErrorListener
;
...
@@ -934,7 +1124,7 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -934,7 +1124,7 @@ class _SwitchPainter extends ToggleablePainter {
color:
color
,
color:
color
,
image:
image
==
null
?
null
:
DecorationImage
(
image:
image
,
onError:
errorListener
),
image:
image
==
null
?
null
:
DecorationImage
(
image:
image
,
onError:
errorListener
),
shape:
BoxShape
.
circle
,
shape:
BoxShape
.
circle
,
boxShadow:
kElevationToShadow
[
1
]
,
boxShadow:
thumbShadow
,
);
);
}
}
...
@@ -952,7 +1142,6 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -952,7 +1142,6 @@ class _SwitchPainter extends ToggleablePainter {
@override
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
void
paint
(
Canvas
canvas
,
Size
size
)
{
final
bool
isEnabled
=
isInteractive
;
final
double
currentValue
=
position
.
value
;
final
double
currentValue
=
position
.
value
;
final
double
visualPosition
;
final
double
visualPosition
;
...
@@ -965,29 +1154,32 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -965,29 +1154,32 @@ class _SwitchPainter extends ToggleablePainter {
break
;
break
;
}
}
final
double
thumbRadius
=
isPressed
?
pressedThumbRadius
:
lerpDouble
(
inactiveThumbRadius
,
activeThumbRadius
,
currentValue
)!;
final
Color
trackColor
=
Color
.
lerp
(
inactiveTrackColor
,
activeTrackColor
,
currentValue
)!;
final
Color
trackColor
=
Color
.
lerp
(
inactiveTrackColor
,
activeTrackColor
,
currentValue
)!;
final
Color
?
trackOutlineColor
=
inactiveTrackOutlineColor
==
null
?
null
:
Color
.
lerp
(
inactiveTrackOutlineColor
,
Colors
.
transparent
,
currentValue
);
final
Color
lerpedThumbColor
=
Color
.
lerp
(
inactiveColor
,
activeColor
,
currentValue
)!;
final
Color
lerpedThumbColor
=
Color
.
lerp
(
inactiveColor
,
activeColor
,
currentValue
)!;
// Blend the thumb color against a `surfaceColor` background in case the
// Blend the thumb color against a `surfaceColor` background in case the
// thumbColor is not opaque. This way we do not see through the thumb to the
// thumbColor is not opaque. This way we do not see through the thumb to the
// track underneath.
// track underneath.
final
Color
thumbColor
=
Color
.
alphaBlend
(
lerpedThumbColor
,
surfaceColor
);
final
Color
thumbColor
=
Color
.
alphaBlend
(
lerpedThumbColor
,
surfaceColor
);
final
ImageProvider
?
thumbImage
=
isEnabled
final
Icon
?
thumbIcon
=
currentValue
<
0.5
?
inactiveIcon
:
activeIcon
;
?
(
currentValue
<
0.5
?
inactiveThumbImage
:
activeThumbImage
)
:
inactiveThumbImage
;
final
Image
ErrorListener
?
thumbErrorListener
=
isEnabled
final
Image
Provider
?
thumbImage
=
currentValue
<
0.5
?
inactiveThumbImage
:
activeThumbImage
;
?
(
currentValue
<
0.5
?
onInactiveThumbImageError
:
onActiveThumbImageError
)
:
onIna
ctiveThumbImageError
;
final
ImageErrorListener
?
thumbErrorListener
=
currentValue
<
0.5
?
onInactiveThumbImageError
:
onA
ctiveThumbImageError
;
final
Paint
paint
=
Paint
()
final
Paint
paint
=
Paint
()
..
color
=
trackColor
;
..
color
=
trackColor
;
final
Offset
trackPaintOffset
=
_computeTrackPaintOffset
(
size
,
_kTrackWidth
,
_kT
rackHeight
);
final
Offset
trackPaintOffset
=
_computeTrackPaintOffset
(
size
,
trackWidth
,
t
rackHeight
);
final
Offset
thumbPaintOffset
=
_computeThumbPaintOffset
(
trackPaintOffset
,
visualPosition
);
final
Offset
thumbPaintOffset
=
_computeThumbPaintOffset
(
trackPaintOffset
,
visualPosition
);
final
Offset
radialReactionOrigin
=
Offset
(
thumbPaintOffset
.
dx
+
_kT
humbRadius
,
size
.
height
/
2
);
final
Offset
radialReactionOrigin
=
Offset
(
thumbPaintOffset
.
dx
+
t
humbRadius
,
size
.
height
/
2
);
_paintTrackWith
(
canvas
,
paint
,
trackPaintOffset
);
_paintTrackWith
(
canvas
,
paint
,
trackPaintOffset
,
trackOutlineColor
);
paintRadialReaction
(
canvas:
canvas
,
origin:
radialReactionOrigin
);
paintRadialReaction
(
canvas:
canvas
,
origin:
radialReactionOrigin
);
_paintThumbWith
(
_paintThumbWith
(
thumbPaintOffset
,
thumbPaintOffset
,
...
@@ -996,13 +1188,15 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -996,13 +1188,15 @@ class _SwitchPainter extends ToggleablePainter {
thumbColor
,
thumbColor
,
thumbImage
,
thumbImage
,
thumbErrorListener
,
thumbErrorListener
,
thumbRadius
,
thumbIcon
,
);
);
}
}
/// Computes canvas offset for track's upper left corner
/// Computes canvas offset for track's upper left corner
Offset
_computeTrackPaintOffset
(
Size
canvasSize
,
double
trackWidth
,
double
trackHeight
)
{
Offset
_computeTrackPaintOffset
(
Size
canvasSize
,
double
trackWidth
,
double
trackHeight
)
{
final
double
horizontalOffset
=
(
canvasSize
.
width
-
_kT
rackWidth
)
/
2.0
;
final
double
horizontalOffset
=
(
canvasSize
.
width
-
t
rackWidth
)
/
2.0
;
final
double
verticalOffset
=
(
canvasSize
.
height
-
_kT
rackHeight
)
/
2.0
;
final
double
verticalOffset
=
(
canvasSize
.
height
-
t
rackHeight
)
/
2.0
;
return
Offset
(
horizontalOffset
,
verticalOffset
);
return
Offset
(
horizontalOffset
,
verticalOffset
);
}
}
...
@@ -1011,7 +1205,9 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -1011,7 +1205,9 @@ class _SwitchPainter extends ToggleablePainter {
/// square
/// square
Offset
_computeThumbPaintOffset
(
Offset
trackPaintOffset
,
double
visualPosition
)
{
Offset
_computeThumbPaintOffset
(
Offset
trackPaintOffset
,
double
visualPosition
)
{
// How much thumb radius extends beyond the track
// How much thumb radius extends beyond the track
const
double
additionalThumbRadius
=
_kThumbRadius
-
_kTrackRadius
;
final
double
trackRadius
=
trackHeight
/
2
;
final
double
thumbRadius
=
isPressed
?
pressedThumbRadius
:
lerpDouble
(
inactiveThumbRadius
,
activeThumbRadius
,
position
.
value
)!;
final
double
additionalThumbRadius
=
thumbRadius
-
trackRadius
;
final
double
horizontalProgress
=
visualPosition
*
trackInnerLength
;
final
double
horizontalProgress
=
visualPosition
*
trackInnerLength
;
final
double
thumbHorizontalOffset
=
trackPaintOffset
.
dx
-
additionalThumbRadius
+
horizontalProgress
;
final
double
thumbHorizontalOffset
=
trackPaintOffset
.
dx
-
additionalThumbRadius
+
horizontalProgress
;
...
@@ -1020,19 +1216,39 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -1020,19 +1216,39 @@ class _SwitchPainter extends ToggleablePainter {
return
Offset
(
thumbHorizontalOffset
,
thumbVerticalOffset
);
return
Offset
(
thumbHorizontalOffset
,
thumbVerticalOffset
);
}
}
void
_paintTrackWith
(
Canvas
canvas
,
Paint
paint
,
Offset
trackPaintOffset
)
{
void
_paintTrackWith
(
Canvas
canvas
,
Paint
paint
,
Offset
trackPaintOffset
,
Color
?
trackOutlineColor
)
{
final
Rect
trackRect
=
Rect
.
fromLTWH
(
final
Rect
trackRect
=
Rect
.
fromLTWH
(
trackPaintOffset
.
dx
,
trackPaintOffset
.
dx
,
trackPaintOffset
.
dy
,
trackPaintOffset
.
dy
,
_kT
rackWidth
,
t
rackWidth
,
_kT
rackHeight
,
t
rackHeight
,
);
);
final
double
trackRadius
=
trackHeight
/
2
;
final
RRect
trackRRect
=
RRect
.
fromRectAndRadius
(
final
RRect
trackRRect
=
RRect
.
fromRectAndRadius
(
trackRect
,
trackRect
,
const
Radius
.
circular
(
_kT
rackRadius
),
Radius
.
circular
(
t
rackRadius
),
);
);
canvas
.
drawRRect
(
trackRRect
,
paint
);
canvas
.
drawRRect
(
trackRRect
,
paint
);
if
(
trackOutlineColor
!=
null
)
{
// paint track outline
final
Rect
outlineTrackRect
=
Rect
.
fromLTWH
(
trackPaintOffset
.
dx
+
1
,
trackPaintOffset
.
dy
+
1
,
trackWidth
-
2
,
trackHeight
-
2
,
);
final
RRect
outlineTrackRRect
=
RRect
.
fromRectAndRadius
(
outlineTrackRect
,
Radius
.
circular
(
trackRadius
),
);
final
Paint
outlinePaint
=
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2
..
color
=
trackOutlineColor
;
canvas
.
drawRRect
(
outlineTrackRRect
,
outlinePaint
);
}
}
}
void
_paintThumbWith
(
void
_paintThumbWith
(
...
@@ -1042,6 +1258,8 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -1042,6 +1258,8 @@ class _SwitchPainter extends ToggleablePainter {
Color
thumbColor
,
Color
thumbColor
,
ImageProvider
?
thumbImage
,
ImageProvider
?
thumbImage
,
ImageErrorListener
?
thumbErrorListener
,
ImageErrorListener
?
thumbErrorListener
,
double
thumbRadius
,
Icon
?
thumbIcon
,
)
{
)
{
try
{
try
{
_isPainting
=
true
;
_isPainting
=
true
;
...
@@ -1056,13 +1274,51 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -1056,13 +1274,51 @@ class _SwitchPainter extends ToggleablePainter {
// The thumb contracts slightly during the animation
// The thumb contracts slightly during the animation
final
double
inset
=
1.0
-
(
currentValue
-
0.5
).
abs
()
*
2.0
;
final
double
inset
=
1.0
-
(
currentValue
-
0.5
).
abs
()
*
2.0
;
final
double
radius
=
_kT
humbRadius
-
inset
;
final
double
radius
=
t
humbRadius
-
inset
;
thumbPainter
.
paint
(
thumbPainter
.
paint
(
canvas
,
canvas
,
thumbPaintOffset
+
Offset
(
0
,
inset
),
thumbPaintOffset
+
Offset
(
0
,
inset
),
configuration
.
copyWith
(
size:
Size
.
fromRadius
(
radius
)),
configuration
.
copyWith
(
size:
Size
.
fromRadius
(
radius
)),
);
);
if
(
thumbIcon
!=
null
&&
thumbIcon
.
icon
!=
null
)
{
final
Color
iconColor
=
Color
.
lerp
(
inactiveIconColor
,
activeIconColor
,
currentValue
)!;
final
double
iconSize
=
thumbIcon
.
size
??
_SwitchConfigM3
.
iconSize
;
final
IconData
iconData
=
thumbIcon
.
icon
!;
final
double
?
iconWeight
=
thumbIcon
.
weight
??
iconTheme
?.
weight
;
final
double
?
iconFill
=
thumbIcon
.
fill
??
iconTheme
?.
fill
;
final
double
?
iconGrade
=
thumbIcon
.
grade
??
iconTheme
?.
grade
;
final
double
?
iconOpticalSize
=
thumbIcon
.
opticalSize
??
iconTheme
?.
opticalSize
;
final
List
<
Shadow
>?
iconShadows
=
thumbIcon
.
shadows
??
iconTheme
?.
shadows
;
final
TextSpan
textSpan
=
TextSpan
(
text:
String
.
fromCharCode
(
iconData
.
codePoint
),
style:
TextStyle
(
fontVariations:
<
FontVariation
>[
if
(
iconFill
!=
null
)
FontVariation
(
'FILL'
,
iconFill
),
if
(
iconWeight
!=
null
)
FontVariation
(
'wght'
,
iconWeight
),
if
(
iconGrade
!=
null
)
FontVariation
(
'GRAD'
,
iconGrade
),
if
(
iconOpticalSize
!=
null
)
FontVariation
(
'opsz'
,
iconOpticalSize
),
],
color:
iconColor
,
fontSize:
iconSize
,
inherit:
false
,
fontFamily:
iconData
.
fontFamily
,
package:
iconData
.
fontPackage
,
shadows:
iconShadows
,
),
);
final
TextPainter
textPainter
=
TextPainter
(
textDirection:
textDirection
,
text:
textSpan
,
);
textPainter
.
layout
();
final
double
additionalIconRadius
=
thumbRadius
-
iconSize
/
2
;
final
Offset
offset
=
thumbPaintOffset
+
Offset
(
additionalIconRadius
,
additionalIconRadius
);
textPainter
.
paint
(
canvas
,
offset
);
}
}
finally
{
}
finally
{
_isPainting
=
false
;
_isPainting
=
false
;
}
}
...
@@ -1078,3 +1334,330 @@ class _SwitchPainter extends ToggleablePainter {
...
@@ -1078,3 +1334,330 @@ class _SwitchPainter extends ToggleablePainter {
super
.
dispose
();
super
.
dispose
();
}
}
}
}
mixin
_SwitchConfig
{
double
get
trackHeight
;
double
get
trackWidth
;
double
get
switchWidth
;
double
get
switchHeight
;
double
get
switchHeightCollapsed
;
double
get
activeThumbRadius
;
double
get
inactiveThumbRadius
;
double
get
pressedThumbRadius
;
double
get
thumbRadiusWithIcon
;
List
<
BoxShadow
>?
get
thumbShadow
;
MaterialStateProperty
<
Color
?>?
get
trackOutlineColor
;
MaterialStateProperty
<
Color
>
get
iconColor
;
}
// Hand coded defaults based on Material Design 2.
class
_SwitchConfigM2
with
_SwitchConfig
{
_SwitchConfigM2
();
@override
double
get
activeThumbRadius
=>
10.0
;
@override
MaterialStateProperty
<
Color
>
get
iconColor
=>
MaterialStateProperty
.
all
<
Color
>(
Colors
.
transparent
);
@override
double
get
inactiveThumbRadius
=>
10.0
;
@override
double
get
pressedThumbRadius
=>
10.0
;
@override
double
get
switchHeight
=>
_kSwitchMinSize
+
8.0
;
@override
double
get
switchHeightCollapsed
=>
_kSwitchMinSize
;
@override
double
get
switchWidth
=>
trackWidth
-
2
*
(
trackHeight
/
2.0
)
+
_kSwitchMinSize
;
@override
double
get
thumbRadiusWithIcon
=>
10.0
;
@override
List
<
BoxShadow
>?
get
thumbShadow
=>
kElevationToShadow
[
1
];
@override
double
get
trackHeight
=>
14.0
;
@override
MaterialStateProperty
<
Color
?>?
get
trackOutlineColor
=>
null
;
@override
double
get
trackWidth
=>
33.0
;
}
class
_SwitchDefaultsM2
extends
SwitchThemeData
{
_SwitchDefaultsM2
(
BuildContext
context
)
:
_theme
=
Theme
.
of
(
context
),
_colors
=
Theme
.
of
(
context
).
colorScheme
;
final
ThemeData
_theme
;
final
ColorScheme
_colors
;
@override
MaterialStateProperty
<
Color
>
get
thumbColor
{
final
bool
isDark
=
_theme
.
brightness
==
Brightness
.
dark
;
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
isDark
?
Colors
.
grey
.
shade800
:
Colors
.
grey
.
shade400
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
_colors
.
secondary
;
}
return
isDark
?
Colors
.
grey
.
shade400
:
Colors
.
grey
.
shade50
;
});
}
@override
MaterialStateProperty
<
Color
>
get
trackColor
{
final
bool
isDark
=
_theme
.
brightness
==
Brightness
.
dark
;
const
Color
black32
=
Color
(
0x52000000
);
// Black with 32% opacity
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
isDark
?
Colors
.
white10
:
Colors
.
black12
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
final
Color
activeColor
=
_colors
.
secondary
;
return
activeColor
.
withAlpha
(
0x80
);
}
return
isDark
?
Colors
.
white30
:
black32
;
});
}
@override
MaterialTapTargetSize
get
materialTapTargetSize
=>
_theme
.
materialTapTargetSize
;
@override
MaterialStateProperty
<
MouseCursor
>
get
mouseCursor
=>
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
=>
MaterialStateMouseCursor
.
clickable
.
resolve
(
states
));
@override
MaterialStateProperty
<
Color
?>
get
overlayColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
thumbColor
.
resolve
(
states
).
withAlpha
(
kRadialReactionAlpha
);
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_theme
.
focusColor
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_theme
.
hoverColor
;
}
return
null
;
});
}
@override
double
get
splashRadius
=>
kRadialReactionRadius
;
}
// BEGIN GENERATED TOKEN PROPERTIES - Switch
// Do not edit by hand. The code between the "BEGIN GENERATED" and
// "END GENERATED" comments are generated from data in the Material
// Design token database by the script:
// dev/tools/gen_defaults/bin/gen_defaults.dart.
// Token database version: v0_101
class
_SwitchDefaultsM3
extends
SwitchThemeData
{
_SwitchDefaultsM3
(
BuildContext
context
)
:
_colors
=
Theme
.
of
(
context
).
colorScheme
;
final
ColorScheme
_colors
;
@override
MaterialStateProperty
<
Color
>
get
thumbColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
_colors
.
surface
.
withOpacity
(
1.0
);
}
return
_colors
.
onSurface
.
withOpacity
(
0.38
);
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
primaryContainer
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
primaryContainer
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
primaryContainer
;
}
return
_colors
.
onPrimary
;
}
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
onSurfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
onSurfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
onSurfaceVariant
;
}
return
_colors
.
outline
;
});
}
@override
MaterialStateProperty
<
Color
>
get
trackColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.12
);
}
return
_colors
.
surfaceVariant
.
withOpacity
(
0.12
);
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
primary
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
primary
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
primary
;
}
return
_colors
.
primary
;
}
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
surfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
surfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
surfaceVariant
;
}
return
_colors
.
surfaceVariant
;
});
}
@override
MaterialStateProperty
<
Color
?>
get
overlayColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
primary
.
withOpacity
(
0.12
);
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
primary
.
withOpacity
(
0.08
);
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
primary
.
withOpacity
(
0.12
);
}
return
null
;
}
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.12
);
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.08
);
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.12
);
}
return
null
;
});
}
@override
double
get
splashRadius
=>
40.0
/
2
;
}
class
_SwitchConfigM3
with
_SwitchConfig
{
_SwitchConfigM3
(
this
.
context
)
:
_colors
=
Theme
.
of
(
context
).
colorScheme
;
BuildContext
context
;
final
ColorScheme
_colors
;
static
const
double
iconSize
=
16.0
;
@override
double
get
activeThumbRadius
=>
24.0
/
2
;
@override
MaterialStateProperty
<
Color
>
get
iconColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.38
);
}
return
_colors
.
surfaceVariant
.
withOpacity
(
0.38
);
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
onPrimaryContainer
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
onPrimaryContainer
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
onPrimaryContainer
;
}
return
_colors
.
onPrimaryContainer
;
}
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
surfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
surfaceVariant
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
surfaceVariant
;
}
return
_colors
.
surfaceVariant
;
});
}
@override
double
get
inactiveThumbRadius
=>
16.0
/
2
;
@override
double
get
pressedThumbRadius
=>
28.0
/
2
;
@override
double
get
switchHeight
=>
_kSwitchMinSize
+
8.0
;
@override
double
get
switchHeightCollapsed
=>
_kSwitchMinSize
;
@override
double
get
switchWidth
=>
trackWidth
-
2
*
(
trackHeight
/
2.0
)
+
_kSwitchMinSize
;
@override
double
get
thumbRadiusWithIcon
=>
24.0
/
2
;
@override
List
<
BoxShadow
>?
get
thumbShadow
=>
kElevationToShadow
[
0
];
@override
double
get
trackHeight
=>
32.0
;
@override
MaterialStateProperty
<
Color
?>
get
trackOutlineColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
null
;
}
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.12
);
}
return
_colors
.
outline
;
});
}
@override
double
get
trackWidth
=>
52.0
;
}
// END GENERATED TOKEN PROPERTIES - Switch
packages/flutter/lib/src/material/switch_theme.dart
View file @
75fac6ae
...
@@ -43,6 +43,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -43,6 +43,7 @@ class SwitchThemeData with Diagnosticable {
this
.
mouseCursor
,
this
.
mouseCursor
,
this
.
overlayColor
,
this
.
overlayColor
,
this
.
splashRadius
,
this
.
splashRadius
,
this
.
thumbIcon
,
});
});
/// {@macro flutter.material.switch.thumbColor}
/// {@macro flutter.material.switch.thumbColor}
...
@@ -76,6 +77,11 @@ class SwitchThemeData with Diagnosticable {
...
@@ -76,6 +77,11 @@ class SwitchThemeData with Diagnosticable {
/// If specified, overrides the default value of [Switch.splashRadius].
/// If specified, overrides the default value of [Switch.splashRadius].
final
double
?
splashRadius
;
final
double
?
splashRadius
;
/// {@macro flutter.material.switch.thumbIcon}
///
/// It is overridden by [Switch.thumbIcon].
final
MaterialStateProperty
<
Icon
?>?
thumbIcon
;
/// Creates a copy of this object but with the given fields replaced with the
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
/// new values.
SwitchThemeData
copyWith
({
SwitchThemeData
copyWith
({
...
@@ -85,6 +91,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -85,6 +91,7 @@ class SwitchThemeData with Diagnosticable {
MaterialStateProperty
<
MouseCursor
?>?
mouseCursor
,
MaterialStateProperty
<
MouseCursor
?>?
mouseCursor
,
MaterialStateProperty
<
Color
?>?
overlayColor
,
MaterialStateProperty
<
Color
?>?
overlayColor
,
double
?
splashRadius
,
double
?
splashRadius
,
MaterialStateProperty
<
Icon
?>?
thumbIcon
,
})
{
})
{
return
SwitchThemeData
(
return
SwitchThemeData
(
thumbColor:
thumbColor
??
this
.
thumbColor
,
thumbColor:
thumbColor
??
this
.
thumbColor
,
...
@@ -93,6 +100,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -93,6 +100,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor:
mouseCursor
??
this
.
mouseCursor
,
mouseCursor:
mouseCursor
??
this
.
mouseCursor
,
overlayColor:
overlayColor
??
this
.
overlayColor
,
overlayColor:
overlayColor
??
this
.
overlayColor
,
splashRadius:
splashRadius
??
this
.
splashRadius
,
splashRadius:
splashRadius
??
this
.
splashRadius
,
thumbIcon:
thumbIcon
??
this
.
thumbIcon
,
);
);
}
}
...
@@ -107,6 +115,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -107,6 +115,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor:
t
<
0.5
?
a
?.
mouseCursor
:
b
?.
mouseCursor
,
mouseCursor:
t
<
0.5
?
a
?.
mouseCursor
:
b
?.
mouseCursor
,
overlayColor:
MaterialStateProperty
.
lerp
<
Color
?>(
a
?.
overlayColor
,
b
?.
overlayColor
,
t
,
Color
.
lerp
),
overlayColor:
MaterialStateProperty
.
lerp
<
Color
?>(
a
?.
overlayColor
,
b
?.
overlayColor
,
t
,
Color
.
lerp
),
splashRadius:
lerpDouble
(
a
?.
splashRadius
,
b
?.
splashRadius
,
t
),
splashRadius:
lerpDouble
(
a
?.
splashRadius
,
b
?.
splashRadius
,
t
),
thumbIcon:
t
<
0.5
?
a
?.
thumbIcon
:
b
?.
thumbIcon
,
);
);
}
}
...
@@ -118,6 +127,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -118,6 +127,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor
,
mouseCursor
,
overlayColor
,
overlayColor
,
splashRadius
,
splashRadius
,
thumbIcon
,
);
);
@override
@override
...
@@ -134,7 +144,8 @@ class SwitchThemeData with Diagnosticable {
...
@@ -134,7 +144,8 @@ class SwitchThemeData with Diagnosticable {
&&
other
.
materialTapTargetSize
==
materialTapTargetSize
&&
other
.
materialTapTargetSize
==
materialTapTargetSize
&&
other
.
mouseCursor
==
mouseCursor
&&
other
.
mouseCursor
==
mouseCursor
&&
other
.
overlayColor
==
overlayColor
&&
other
.
overlayColor
==
overlayColor
&&
other
.
splashRadius
==
splashRadius
;
&&
other
.
splashRadius
==
splashRadius
&&
other
.
thumbIcon
==
thumbIcon
;
}
}
@override
@override
...
@@ -146,6 +157,7 @@ class SwitchThemeData with Diagnosticable {
...
@@ -146,6 +157,7 @@ class SwitchThemeData with Diagnosticable {
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
MouseCursor
?>>(
'mouseCursor'
,
mouseCursor
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
MouseCursor
?>>(
'mouseCursor'
,
mouseCursor
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
Color
?>>(
'overlayColor'
,
overlayColor
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
Color
?>>(
'overlayColor'
,
overlayColor
,
defaultValue:
null
));
properties
.
add
(
DoubleProperty
(
'splashRadius'
,
splashRadius
,
defaultValue:
null
));
properties
.
add
(
DoubleProperty
(
'splashRadius'
,
splashRadius
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
Icon
?>>(
'thumbIcon'
,
thumbIcon
,
defaultValue:
null
));
}
}
}
}
...
...
packages/flutter/lib/src/material/theme_data.dart
View file @
75fac6ae
...
@@ -1252,7 +1252,7 @@ class ThemeData with Diagnosticable {
...
@@ -1252,7 +1252,7 @@ class ThemeData with Diagnosticable {
/// * Typography: `typography` (see table above)
/// * Typography: `typography` (see table above)
///
///
/// ### Components
/// ### Components
/// * Common buttons: [ElevatedButton], [FilledButton], [OutlinedButton], [TextButton]
/// * Common buttons: [ElevatedButton], [FilledButton], [OutlinedButton], [TextButton]
, [IconButton]
/// * FAB: [FloatingActionButton]
/// * FAB: [FloatingActionButton]
/// * Extended FAB: [FloatingActionButton.extended]
/// * Extended FAB: [FloatingActionButton.extended]
/// * Cards: [Card]
/// * Cards: [Card]
...
@@ -1266,6 +1266,7 @@ class ThemeData with Diagnosticable {
...
@@ -1266,6 +1266,7 @@ class ThemeData with Diagnosticable {
/// * Lists: [ListTile]
/// * Lists: [ListTile]
/// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar])
/// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar])
/// * [Navigation rail](https://m3.material.io/components/navigation-rail): [NavigationRail]
/// * [Navigation rail](https://m3.material.io/components/navigation-rail): [NavigationRail]
/// * Switch: [Switch]
/// * Top app bar: [AppBar]
/// * Top app bar: [AppBar]
///
///
/// In addition, this flag enables features introduced in Android 12.
/// In addition, this flag enables features introduced in Android 12.
...
...
packages/flutter/test/material/switch_test.dart
View file @
75fac6ae
...
@@ -21,6 +21,8 @@ import '../rendering/mock_canvas.dart';
...
@@ -21,6 +21,8 @@ import '../rendering/mock_canvas.dart';
import
'../widgets/semantics_tester.dart'
;
import
'../widgets/semantics_tester.dart'
;
void
main
(
)
{
void
main
(
)
{
final
ThemeData
theme
=
ThemeData
();
testWidgets
(
'Switch can toggle on tap'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Switch can toggle on tap'
,
(
WidgetTester
tester
)
async
{
final
Key
switchKey
=
UniqueKey
();
final
Key
switchKey
=
UniqueKey
();
bool
value
=
false
;
bool
value
=
false
;
...
@@ -30,7 +32,9 @@ void main() {
...
@@ -30,7 +32,9 @@ void main() {
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
return
MaterialApp
(
theme:
theme
,
home:
Material
(
child:
Center
(
child:
Center
(
child:
Switch
(
child:
Switch
(
dragStartBehavior:
DragStartBehavior
.
down
,
dragStartBehavior:
DragStartBehavior
.
down
,
...
@@ -43,6 +47,7 @@ void main() {
...
@@ -43,6 +47,7 @@ void main() {
},
},
),
),
),
),
),
);
);
},
},
),
),
...
@@ -55,9 +60,10 @@ void main() {
...
@@ -55,9 +60,10 @@ void main() {
});
});
testWidgets
(
'Switch size is configurable by ThemeData.materialTapTargetSize'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Switch size is configurable by ThemeData.materialTapTargetSize'
,
(
WidgetTester
tester
)
async
{
final
bool
material3
=
theme
.
useMaterial3
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Theme
(
Theme
(
data:
ThemeData
(
materialTapTargetSize:
MaterialTapTargetSize
.
padded
),
data:
theme
.
copyWith
(
materialTapTargetSize:
MaterialTapTargetSize
.
padded
),
child:
Directionality
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
Material
(
child:
Material
(
...
@@ -73,11 +79,14 @@ void main() {
...
@@ -73,11 +79,14 @@ void main() {
),
),
);
);
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
const
Size
(
59.0
,
48.0
));
// switch width = trackWidth - 2 * trackRadius + _kSwitchMinSize
// M2 width = 33 - 2 * 7 + 40
// M3 width = 52 - 2 * 16 + 40
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
material3
?
const
Size
(
60.0
,
48.0
)
:
const
Size
(
59.0
,
48.0
));
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Theme
(
Theme
(
data:
ThemeData
(
materialTapTargetSize:
MaterialTapTargetSize
.
shrinkWrap
),
data:
theme
.
copyWith
(
materialTapTargetSize:
MaterialTapTargetSize
.
shrinkWrap
),
child:
Directionality
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
Material
(
child:
Material
(
...
@@ -93,10 +102,10 @@ void main() {
...
@@ -93,10 +102,10 @@ void main() {
),
),
);
);
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
const
Size
(
59.0
,
40.0
));
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
material3
?
const
Size
(
60.0
,
40.0
)
:
const
Size
(
59.0
,
40.0
));
});
});
testWidgets
(
'Switch does not get distorted upon changing constraints with parent'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Switch does not get distorted upon changing constraints with parent
- M2
'
,
(
WidgetTester
tester
)
async
{
const
double
maxWidth
=
300
;
const
double
maxWidth
=
300
;
const
double
maxHeight
=
100
;
const
double
maxHeight
=
100
;
...
@@ -151,7 +160,9 @@ void main() {
...
@@ -151,7 +160,9 @@ void main() {
bool
value
=
false
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -171,6 +182,7 @@ void main() {
...
@@ -171,6 +182,7 @@ void main() {
},
},
),
),
),
),
),
);
);
expect
(
value
,
isFalse
);
expect
(
value
,
isFalse
);
...
@@ -198,7 +210,9 @@ void main() {
...
@@ -198,7 +210,9 @@ void main() {
bool
value
=
false
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -218,6 +232,7 @@ void main() {
...
@@ -218,6 +232,7 @@ void main() {
},
},
),
),
),
),
),
);
);
expect
(
value
,
isFalse
);
expect
(
value
,
isFalse
);
...
@@ -287,7 +302,9 @@ void main() {
...
@@ -287,7 +302,9 @@ void main() {
bool
value
=
false
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
rtl
,
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -307,6 +324,7 @@ void main() {
...
@@ -307,6 +324,7 @@ void main() {
},
},
),
),
),
),
),
);
);
await
tester
.
drag
(
find
.
byType
(
Switch
),
const
Offset
(
30.0
,
0.0
));
await
tester
.
drag
(
find
.
byType
(
Switch
),
const
Offset
(
30.0
,
0.0
));
...
@@ -513,7 +531,9 @@ void main() {
...
@@ -513,7 +531,9 @@ void main() {
bool
value
=
false
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
MaterialApp
(
theme:
theme
,
home:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -533,6 +553,7 @@ void main() {
...
@@ -533,6 +553,7 @@ void main() {
},
},
),
),
),
),
),
);
);
expect
(
value
,
isFalse
);
expect
(
value
,
isFalse
);
...
@@ -554,7 +575,9 @@ void main() {
...
@@ -554,7 +575,9 @@ void main() {
bool
value
=
false
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -574,6 +597,7 @@ void main() {
...
@@ -574,6 +597,7 @@ void main() {
},
},
),
),
),
),
),
);
);
// Move a little to the right, not past the middle.
// Move a little to the right, not past the middle.
...
@@ -637,7 +661,9 @@ void main() {
...
@@ -637,7 +661,9 @@ void main() {
final
SemanticsTester
semanticsTester
=
SemanticsTester
(
tester
);
final
SemanticsTester
semanticsTester
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -656,6 +682,7 @@ void main() {
...
@@ -656,6 +682,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
(
Switch
));
...
@@ -682,6 +709,7 @@ void main() {
...
@@ -682,6 +709,7 @@ void main() {
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
StatefulBuilder
(
home:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
void
onChanged
(
bool
newValue
)
{
void
onChanged
(
bool
newValue
)
{
...
@@ -859,6 +887,7 @@ void main() {
...
@@ -859,6 +887,7 @@ void main() {
const
double
splashRadius
=
30
;
const
double
splashRadius
=
30
;
Widget
buildApp
()
{
Widget
buildApp
()
{
return
MaterialApp
(
return
MaterialApp
(
theme:
theme
,
home:
Material
(
home:
Material
(
child:
Center
(
child:
Center
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -962,6 +991,7 @@ void main() {
...
@@ -962,6 +991,7 @@ void main() {
bool
value
=
true
;
bool
value
=
true
;
Widget
buildApp
({
bool
enabled
=
true
})
{
Widget
buildApp
({
bool
enabled
=
true
})
{
return
MaterialApp
(
return
MaterialApp
(
theme:
theme
,
home:
Material
(
home:
Material
(
child:
Center
(
child:
Center
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -1001,6 +1031,7 @@ void main() {
...
@@ -1001,6 +1031,7 @@ void main() {
// Test Switch.adaptive() constructor
// Test Switch.adaptive() constructor
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
Scaffold
(
home:
Scaffold
(
body:
Align
(
body:
Align
(
alignment:
Alignment
.
topLeft
,
alignment:
Alignment
.
topLeft
,
...
@@ -1029,6 +1060,7 @@ void main() {
...
@@ -1029,6 +1060,7 @@ void main() {
// Test Switch() constructor
// Test Switch() constructor
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
Scaffold
(
home:
Scaffold
(
body:
Align
(
body:
Align
(
alignment:
Alignment
.
topLeft
,
alignment:
Alignment
.
topLeft
,
...
@@ -1053,6 +1085,7 @@ void main() {
...
@@ -1053,6 +1085,7 @@ void main() {
// Test default cursor
// Test default cursor
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
Scaffold
(
home:
Scaffold
(
body:
Align
(
body:
Align
(
alignment:
Alignment
.
topLeft
,
alignment:
Alignment
.
topLeft
,
...
@@ -1074,8 +1107,9 @@ void main() {
...
@@ -1074,8 +1107,9 @@ void main() {
// Test default cursor when disabled
// Test default cursor when disabled
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
const
MaterialApp
(
MaterialApp
(
home:
Scaffold
(
theme:
theme
,
home:
const
Scaffold
(
body:
Align
(
body:
Align
(
alignment:
Alignment
.
topLeft
,
alignment:
Alignment
.
topLeft
,
child:
Material
(
child:
Material
(
...
@@ -1103,7 +1137,9 @@ void main() {
...
@@ -1103,7 +1137,9 @@ void main() {
bool
enabled
=
true
;
bool
enabled
=
true
;
late
StateSetter
stateSetter
;
late
StateSetter
stateSetter
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Directionality
(
Theme
(
data:
theme
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
...
@@ -1123,6 +1159,7 @@ void main() {
...
@@ -1123,6 +1159,7 @@ void main() {
},
},
),
),
),
),
),
);
);
final
ToggleableStateMixin
oldSwitchState
=
tester
.
state
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_MaterialSwitch'
));
final
ToggleableStateMixin
oldSwitchState
=
tester
.
state
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
.
runtimeType
.
toString
()
==
'_MaterialSwitch'
));
...
@@ -1580,6 +1617,7 @@ void main() {
...
@@ -1580,6 +1617,7 @@ void main() {
Widget
buildSwitch
({
bool
active
=
false
,
bool
focused
=
false
,
bool
useOverlay
=
true
})
{
Widget
buildSwitch
({
bool
active
=
false
,
bool
focused
=
false
,
bool
useOverlay
=
true
})
{
return
MaterialApp
(
return
MaterialApp
(
theme:
theme
,
home:
Scaffold
(
home:
Scaffold
(
body:
Switch
(
body:
Switch
(
focusNode:
focusNode
,
focusNode:
focusNode
,
...
@@ -1701,6 +1739,7 @@ void main() {
...
@@ -1701,6 +1739,7 @@ void main() {
testWidgets
(
'Do not crash when widget disappears while pointer is down'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Do not crash when widget disappears while pointer is down'
,
(
WidgetTester
tester
)
async
{
Widget
buildSwitch
(
bool
show
)
{
Widget
buildSwitch
(
bool
show
)
{
return
MaterialApp
(
return
MaterialApp
(
theme:
theme
,
home:
Material
(
home:
Material
(
child:
Center
(
child:
Center
(
child:
show
?
Switch
(
value:
true
,
onChanged:
(
_
)
{
})
:
Container
(),
child:
show
?
Switch
(
value:
true
,
onChanged:
(
_
)
{
})
:
Container
(),
...
@@ -1785,11 +1824,53 @@ void main() {
...
@@ -1785,11 +1824,53 @@ void main() {
image
=
await
createTestImage
(
width:
100
,
height:
100
);
image
=
await
createTestImage
(
width:
100
,
height:
100
);
});
});
testWidgets
(
'thumb image shows up'
,
(
WidgetTester
tester
)
async
{
imageCache
.
clear
();
final
_TestImageProvider
provider1
=
_TestImageProvider
();
final
_TestImageProvider
provider2
=
_TestImageProvider
();
expect
(
provider1
.
loadCallCount
,
0
);
expect
(
provider2
.
loadCallCount
,
0
);
bool
value1
=
true
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(
platform:
TargetPlatform
.
android
),
home:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Switch
(
activeThumbImage:
provider1
,
inactiveThumbImage:
provider2
,
value:
value1
,
onChanged:
(
bool
val
)
{
setState
(()
{
value1
=
val
;
});
},
),
);
}
)
)
);
expect
(
provider1
.
loadCallCount
,
1
);
expect
(
provider2
.
loadCallCount
,
0
);
expect
(
imageCache
.
liveImageCount
,
1
);
await
tester
.
tap
(
find
.
byType
(
Switch
));
await
tester
.
pumpAndSettle
();
expect
(
provider1
.
loadCallCount
,
1
);
expect
(
provider2
.
loadCallCount
,
1
);
expect
(
imageCache
.
liveImageCount
,
2
);
});
testWidgets
(
'do not crash when imageProvider completes after Switch is disposed'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'do not crash when imageProvider completes after Switch is disposed'
,
(
WidgetTester
tester
)
async
{
final
DelayedImageProvider
imageProvider
=
DelayedImageProvider
(
image
);
final
DelayedImageProvider
imageProvider
=
DelayedImageProvider
(
image
);
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
Material
(
home:
Material
(
child:
Center
(
child:
Center
(
child:
Switch
(
child:
Switch
(
...
@@ -1819,6 +1900,7 @@ void main() {
...
@@ -1819,6 +1900,7 @@ void main() {
Future
<
void
>
buildSwitch
(
ImageProvider
imageProvider
)
{
Future
<
void
>
buildSwitch
(
ImageProvider
imageProvider
)
{
return
tester
.
pumpWidget
(
return
tester
.
pumpWidget
(
MaterialApp
(
MaterialApp
(
theme:
theme
,
home:
Material
(
home:
Material
(
child:
Center
(
child:
Center
(
child:
Switch
(
child:
Switch
(
...
@@ -1850,27 +1932,933 @@ void main() {
...
@@ -1850,27 +1932,933 @@ void main() {
expect
(
tester
.
takeException
(),
isNull
);
expect
(
tester
.
takeException
(),
isNull
);
});
});
});
});
}
class
DelayedImageProvider
extends
ImageProvider
<
DelayedImageProvider
>
{
group
(
'Switch M3 tests'
,
()
{
DelayedImageProvider
(
this
.
image
);
testWidgets
(
'Switch has default colors when enabled - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
theme
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
theme
.
colorScheme
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
theme
,
home:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
dragStartBehavior:
DragStartBehavior
.
down
,
value:
value
,
onChanged:
(
bool
newValue
)
{
setState
(()
{
value
=
newValue
;
});
},
),
),
);
},
),
),
),
);
final
ui
.
Image
image
;
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
save
()
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
outline
,
rrect:
RRect
.
fromLTRBR
(
5.0
,
9.0
,
55.0
,
39.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
outline
),
// thumb color
reason:
'Inactive enabled switch should match these colors'
,
);
await
tester
.
drag
(
find
.
byType
(
Switch
),
const
Offset
(-
30.0
,
0.0
));
await
tester
.
pump
();
final
Completer
<
ImageInfo
>
_completer
=
Completer
<
ImageInfo
>();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
save
()
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
onPrimary
),
// thumb color
reason:
'Active enabled switch should match these colors'
,
);
});
@override
testWidgets
(
'Inactive Switch has default colors when disabled - M3'
,
(
WidgetTester
tester
)
async
{
Future
<
DelayedImageProvider
>
obtainKey
(
ImageConfiguration
configuration
)
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
return
SynchronousFuture
<
DelayedImageProvider
>(
this
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
}
@override
await
tester
.
pumpWidget
(
MaterialApp
(
ImageStreamCompleter
load
(
DelayedImageProvider
key
,
DecoderCallback
decode
)
{
theme:
themeData
,
return
OneFrameImageStreamCompleter
(
_completer
.
future
);
home:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
const
Material
(
child:
Center
(
child:
Switch
(
value:
false
,
onChanged:
null
,
),
),
);
},
),
),
));
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
save
()
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
5.0
,
9.0
,
55.0
,
39.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Color
.
alphaBlend
(
colors
.
onSurface
.
withOpacity
(
0.38
),
colors
.
surface
)),
// thumb color
reason:
'Inactive disabled switch should match these colors'
,
);
});
testWidgets
(
'Active Switch has default colors when disabled - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
themeData
,
home:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
const
Material
(
child:
Center
(
child:
Switch
(
value:
true
,
onChanged:
null
,
),
),
);
},
),
),
));
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
save
()
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
surface
),
// thumb color
reason:
'Active disabled switch should match these colors'
,
);
});
testWidgets
(
'Switch can be set color - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
bool
value
=
false
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
themeData
,
home:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
dragStartBehavior:
DragStartBehavior
.
down
,
value:
value
,
onChanged:
(
bool
newValue
)
{
setState
(()
{
value
=
newValue
;
});
},
activeColor:
Colors
.
red
[
500
],
activeTrackColor:
Colors
.
green
[
500
],
inactiveThumbColor:
Colors
.
yellow
[
500
],
inactiveTrackColor:
Colors
.
blue
[
500
],
),
),
);
},
),
),
),
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
Colors
.
blue
[
500
],
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
outline
,
)
..
circle
(
color:
Colors
.
yellow
[
500
]),
// thumb color
);
await
tester
.
drag
(
find
.
byType
(
Switch
),
const
Offset
(-
30.0
,
0.0
));
await
tester
.
pump
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
Colors
.
green
[
500
],
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Colors
.
red
[
500
]),
// thumb color
);
});
testWidgets
(
'Switch is focusable and has correct focus color - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
final
FocusNode
focusNode
=
FocusNode
(
debugLabel:
'Switch'
);
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
bool
value
=
true
;
Widget
buildApp
({
bool
enabled
=
true
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Material
(
child:
Center
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Switch
(
value:
value
,
onChanged:
enabled
?
(
bool
newValue
)
{
setState
(()
{
value
=
newValue
;
});
}
:
null
,
focusColor:
Colors
.
orange
[
500
],
autofocus:
true
,
focusNode:
focusNode
,
);
}),
),
),
);
}
}
await
tester
.
pumpWidget
(
buildApp
());
Future
<
void
>
complete
()
async
{
// active, enabled switch
_completer
.
complete
(
ImageInfo
(
image:
image
));
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isTrue
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Colors
.
orange
[
500
]),
);
// Check the false value: inactive enabled switch
value
=
false
;
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isTrue
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
outline
,
rrect:
RRect
.
fromLTRBR
(
5.0
,
9.0
,
55.0
,
39.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Colors
.
orange
[
500
])
);
// Check what happens when disabled: inactive disabled switch.
value
=
false
;
await
tester
.
pumpWidget
(
buildApp
(
enabled:
false
));
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isFalse
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
5.0
,
9.0
,
55.0
,
39.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Color
.
alphaBlend
(
colors
.
onSurface
.
withOpacity
(
0.38
),
colors
.
surface
)),
);
});
testWidgets
(
'Switch can be hovered and has correct hover color - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
bool
value
=
true
;
Widget
buildApp
({
bool
enabled
=
true
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Material
(
child:
Center
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Switch
(
value:
value
,
onChanged:
enabled
?
(
bool
newValue
)
{
setState
(()
{
value
=
newValue
;
});
}
:
null
,
hoverColor:
Colors
.
orange
[
500
],
);
}),
),
),
);
}
// active enabled switch
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
onPrimary
),
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Switch
)));
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
Colors
.
orange
[
500
]),
);
// Check what happens for disabled active switch
await
tester
.
pumpWidget
(
buildApp
(
enabled:
false
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
surface
.
withOpacity
(
1.0
)),
);
});
testWidgets
(
'Switch thumb color resolves in active/enabled states - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
const
Color
activeEnabledThumbColor
=
Color
(
0xFF000001
);
const
Color
activeDisabledThumbColor
=
Color
(
0xFF000002
);
const
Color
inactiveEnabledThumbColor
=
Color
(
0xFF000003
);
const
Color
inactiveDisabledThumbColor
=
Color
(
0xFF000004
);
Color
getThumbColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeDisabledThumbColor
;
}
return
inactiveDisabledThumbColor
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeEnabledThumbColor
;
}
return
inactiveEnabledThumbColor
;
}
final
MaterialStateProperty
<
Color
>
thumbColor
=
MaterialStateColor
.
resolveWith
(
getThumbColor
);
Widget
buildSwitch
({
required
bool
enabled
,
required
bool
active
})
{
return
Theme
(
data:
themeData
,
child:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
thumbColor:
thumbColor
,
value:
active
,
onChanged:
enabled
?
(
_
)
{
}
:
null
,
),
),
);
},
),
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
false
,
active:
false
));
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
rrect
(
style:
PaintingStyle
.
stroke
,
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
5.0
,
9.0
,
55.0
,
39.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
inactiveDisabledThumbColor
),
reason:
'Inactive disabled switch should default track and custom thumb color'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
false
,
active:
true
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
activeDisabledThumbColor
),
reason:
'Active disabled switch should match these colors'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
false
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
surfaceVariant
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
inactiveEnabledThumbColor
),
reason:
'Inactive enabled switch should match these colors'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
true
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
activeEnabledThumbColor
),
reason:
'Active enabled switch should match these colors'
,
);
});
testWidgets
(
'Switch thumb color resolves in hovered/focused states - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
ColorScheme
colors
=
themeData
.
colorScheme
;
final
FocusNode
focusNode
=
FocusNode
(
debugLabel:
'Switch'
);
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
const
Color
hoveredThumbColor
=
Color
(
0xFF000001
);
const
Color
focusedThumbColor
=
Color
(
0xFF000002
);
Color
getThumbColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
hoveredThumbColor
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
focusedThumbColor
;
}
return
Colors
.
transparent
;
}
final
MaterialStateProperty
<
Color
>
thumbColor
=
MaterialStateColor
.
resolveWith
(
getThumbColor
);
Widget
buildSwitch
()
{
return
MaterialApp
(
theme:
themeData
,
home:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
focusNode:
focusNode
,
autofocus:
true
,
value:
true
,
thumbColor:
thumbColor
,
onChanged:
(
_
)
{
},
),
),
);
},
),
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
());
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isTrue
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
primary
.
withOpacity
(
0.12
))
..
circle
(
color:
focusedThumbColor
),
reason:
'active enabled switch should default track and custom thumb color'
,
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Switch
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
style:
PaintingStyle
.
fill
,
color:
colors
.
primary
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
colors
.
primary
.
withOpacity
(
0.08
))
..
circle
(
color:
hoveredThumbColor
),
reason:
'active enabled switch should default track and custom thumb color'
,
);
});
testWidgets
(
'Track color resolves in active/enabled states - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
const
Color
activeEnabledTrackColor
=
Color
(
0xFF000001
);
const
Color
activeDisabledTrackColor
=
Color
(
0xFF000002
);
const
Color
inactiveEnabledTrackColor
=
Color
(
0xFF000003
);
const
Color
inactiveDisabledTrackColor
=
Color
(
0xFF000004
);
Color
getTrackColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeDisabledTrackColor
;
}
return
inactiveDisabledTrackColor
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeEnabledTrackColor
;
}
return
inactiveEnabledTrackColor
;
}
final
MaterialStateProperty
<
Color
>
trackColor
=
MaterialStateColor
.
resolveWith
(
getTrackColor
);
Widget
buildSwitch
({
required
bool
enabled
,
required
bool
active
})
{
return
Theme
(
data:
themeData
,
child:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
trackColor:
trackColor
,
value:
active
,
onChanged:
enabled
?
(
_
)
{
}
:
null
,
),
),
);
},
),
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
false
,
active:
false
));
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
inactiveDisabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Inactive disabled switch track should use this value'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
false
,
active:
true
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
activeDisabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Active disabled switch should match these colors'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
false
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
inactiveEnabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Inactive enabled switch should match these colors'
,
);
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
true
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
activeEnabledTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Active enabled switch should match these colors'
,
);
});
testWidgets
(
'Switch track color resolves in hovered/focused states'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
final
FocusNode
focusNode
=
FocusNode
(
debugLabel:
'Switch'
);
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
const
Color
hoveredTrackColor
=
Color
(
0xFF000001
);
const
Color
focusedTrackColor
=
Color
(
0xFF000002
);
Color
getTrackColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
hoveredTrackColor
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
focusedTrackColor
;
}
return
Colors
.
transparent
;
}
final
MaterialStateProperty
<
Color
>
trackColor
=
MaterialStateColor
.
resolveWith
(
getTrackColor
);
Widget
buildSwitch
()
{
return
Theme
(
data:
themeData
,
child:
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
focusNode:
focusNode
,
autofocus:
true
,
value:
true
,
trackColor:
trackColor
,
onChanged:
(
_
)
{
},
),
),
);
},
),
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
());
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isTrue
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
focusedTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Active enabled switch should match these colors'
,
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Switch
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
hoveredTrackColor
,
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
),
reason:
'Active enabled switch should match these colors'
,
);
});
testWidgets
(
'Switch thumb color is blended against surface color - M3'
,
(
WidgetTester
tester
)
async
{
final
Color
activeDisabledThumbColor
=
Colors
.
blue
.
withOpacity
(.
60
);
final
ThemeData
theme
=
ThemeData
.
light
(
useMaterial3:
true
);
final
ColorScheme
colors
=
theme
.
colorScheme
;
Color
getThumbColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
activeDisabledThumbColor
;
}
return
Colors
.
black
;
}
final
MaterialStateProperty
<
Color
>
thumbColor
=
MaterialStateColor
.
resolveWith
(
getThumbColor
);
Widget
buildSwitch
({
required
bool
enabled
,
required
bool
active
})
{
return
Directionality
(
textDirection:
TextDirection
.
rtl
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Theme
(
data:
theme
,
child:
Material
(
child:
Center
(
child:
Switch
(
thumbColor:
thumbColor
,
value:
active
,
onChanged:
enabled
?
(
_
)
{
}
:
null
,
),
),
),
);
},
),
);
}
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
false
,
active:
true
));
final
Color
expectedThumbColor
=
Color
.
alphaBlend
(
activeDisabledThumbColor
,
theme
.
colorScheme
.
surface
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
(
color:
colors
.
onSurface
.
withOpacity
(
0.12
),
rrect:
RRect
.
fromLTRBR
(
4.0
,
8.0
,
56.0
,
40.0
,
const
Radius
.
circular
(
16.0
)),
)
..
circle
(
color:
expectedThumbColor
),
reason:
'Active disabled thumb color should be blended on top of surface color'
,
);
});
testWidgets
(
'Switch can set icon - M3'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
themeData
=
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
),
brightness:
Brightness
.
light
);
MaterialStateProperty
<
Icon
?>
thumbIcon
(
Icon
?
activeIcon
,
Icon
?
inactiveIcon
)
{
return
MaterialStateProperty
.
resolveWith
<
Icon
?>((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeIcon
;
}
return
inactiveIcon
;
});
}
Widget
buildSwitch
({
required
bool
enabled
,
required
bool
active
,
Icon
?
activeIcon
,
Icon
?
inactiveIcon
})
{
return
Theme
(
data:
themeData
,
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Material
(
child:
Center
(
child:
Switch
(
thumbIcon:
thumbIcon
(
activeIcon
,
inactiveIcon
),
value:
active
,
onChanged:
enabled
?
(
_
)
{}
:
null
,
),
),
);
},
),
),
);
}
// active icon shows when switch is on.
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
true
,
activeIcon:
const
Icon
(
Icons
.
close
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
()..
circle
()
..
paragraph
(
offset:
const
Offset
(
32.0
,
16.0
)),
);
// inactive icon shows when switch is off.
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
false
,
inactiveIcon:
const
Icon
(
Icons
.
close
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
()..
rrect
()
..
circle
()
..
paragraph
(
offset:
const
Offset
(
12.0
,
16.0
)),
);
// active icon doesn't show when switch is off.
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
false
,
activeIcon:
const
Icon
(
Icons
.
check
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
()..
rrect
()..
circle
()
);
// inactive icon doesn't show when switch is on.
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
true
,
inactiveIcon:
const
Icon
(
Icons
.
check
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
()..
circle
()..
restore
(),
);
// without icon
await
tester
.
pumpWidget
(
buildSwitch
(
enabled:
true
,
active:
false
));
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Switch
))),
paints
..
rrect
()..
rrect
()..
circle
()..
restore
(),
);
});
});
}
class
DelayedImageProvider
extends
ImageProvider
<
DelayedImageProvider
>
{
DelayedImageProvider
(
this
.
image
);
final
ui
.
Image
image
;
final
Completer
<
ImageInfo
>
_completer
=
Completer
<
ImageInfo
>();
@override
Future
<
DelayedImageProvider
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
DelayedImageProvider
>(
this
);
}
@override
ImageStreamCompleter
load
(
DelayedImageProvider
key
,
DecoderCallback
decode
)
{
return
OneFrameImageStreamCompleter
(
_completer
.
future
);
}
Future
<
void
>
complete
()
async
{
_completer
.
complete
(
ImageInfo
(
image:
image
));
}
@override
String
toString
()
=>
'
${describeIdentity(this)}
()'
;
}
class
_TestImageProvider
extends
ImageProvider
<
Object
>
{
_TestImageProvider
({
ImageStreamCompleter
?
streamCompleter
})
{
_streamCompleter
=
streamCompleter
??
OneFrameImageStreamCompleter
(
_completer
.
future
);
}
final
Completer
<
ImageInfo
>
_completer
=
Completer
<
ImageInfo
>();
late
ImageStreamCompleter
_streamCompleter
;
bool
get
loadCalled
=>
_loadCallCount
>
0
;
int
get
loadCallCount
=>
_loadCallCount
;
int
_loadCallCount
=
0
;
@override
Future
<
Object
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
_TestImageProvider
>(
this
);
}
@override
void
resolveStreamForKey
(
ImageConfiguration
configuration
,
ImageStream
stream
,
Object
key
,
ImageErrorListener
handleError
)
{
super
.
resolveStreamForKey
(
configuration
,
stream
,
key
,
handleError
);
}
@override
ImageStreamCompleter
load
(
Object
key
,
DecoderCallback
decode
)
{
_loadCallCount
+=
1
;
return
_streamCompleter
;
}
void
complete
(
ui
.
Image
image
)
{
_completer
.
complete
(
ImageInfo
(
image:
image
));
}
void
fail
(
Object
exception
,
StackTrace
?
stackTrace
)
{
_completer
.
completeError
(
exception
,
stackTrace
);
}
}
@override
@override
...
...
packages/flutter/test/material/switch_theme_test.dart
View file @
75fac6ae
...
@@ -23,6 +23,7 @@ void main() {
...
@@ -23,6 +23,7 @@ void main() {
expect
(
themeData
.
materialTapTargetSize
,
null
);
expect
(
themeData
.
materialTapTargetSize
,
null
);
expect
(
themeData
.
overlayColor
,
null
);
expect
(
themeData
.
overlayColor
,
null
);
expect
(
themeData
.
splashRadius
,
null
);
expect
(
themeData
.
splashRadius
,
null
);
expect
(
themeData
.
thumbIcon
,
null
);
const
SwitchTheme
theme
=
SwitchTheme
(
data:
SwitchThemeData
(),
child:
SizedBox
());
const
SwitchTheme
theme
=
SwitchTheme
(
data:
SwitchThemeData
(),
child:
SizedBox
());
expect
(
theme
.
data
.
thumbColor
,
null
);
expect
(
theme
.
data
.
thumbColor
,
null
);
...
@@ -31,6 +32,7 @@ void main() {
...
@@ -31,6 +32,7 @@ void main() {
expect
(
theme
.
data
.
materialTapTargetSize
,
null
);
expect
(
theme
.
data
.
materialTapTargetSize
,
null
);
expect
(
theme
.
data
.
overlayColor
,
null
);
expect
(
theme
.
data
.
overlayColor
,
null
);
expect
(
theme
.
data
.
splashRadius
,
null
);
expect
(
theme
.
data
.
splashRadius
,
null
);
expect
(
theme
.
data
.
thumbIcon
,
null
);
});
});
testWidgets
(
'Default SwitchThemeData debugFillProperties'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Default SwitchThemeData debugFillProperties'
,
(
WidgetTester
tester
)
async
{
...
@@ -54,6 +56,7 @@ void main() {
...
@@ -54,6 +56,7 @@ void main() {
materialTapTargetSize:
MaterialTapTargetSize
.
shrinkWrap
,
materialTapTargetSize:
MaterialTapTargetSize
.
shrinkWrap
,
overlayColor:
MaterialStatePropertyAll
<
Color
>(
Color
(
0xfffffff2
)),
overlayColor:
MaterialStatePropertyAll
<
Color
>(
Color
(
0xfffffff2
)),
splashRadius:
1.0
,
splashRadius:
1.0
,
thumbIcon:
MaterialStatePropertyAll
<
Icon
>(
Icon
(
IconData
(
123
))),
).
debugFillProperties
(
builder
);
).
debugFillProperties
(
builder
);
final
List
<
String
>
description
=
builder
.
properties
final
List
<
String
>
description
=
builder
.
properties
...
@@ -67,6 +70,7 @@ void main() {
...
@@ -67,6 +70,7 @@ void main() {
expect
(
description
[
3
],
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))'
);
expect
(
description
[
3
],
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))'
);
expect
(
description
[
4
],
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))'
);
expect
(
description
[
4
],
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))'
);
expect
(
description
[
5
],
'splashRadius: 1.0'
);
expect
(
description
[
5
],
'splashRadius: 1.0'
);
expect
(
description
[
6
],
'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))'
);
});
});
testWidgets
(
'Switch is themeable'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Switch is themeable'
,
(
WidgetTester
tester
)
async
{
...
@@ -81,10 +85,11 @@ void main() {
...
@@ -81,10 +85,11 @@ void main() {
const
Color
focusOverlayColor
=
Color
(
0xfffffff4
);
const
Color
focusOverlayColor
=
Color
(
0xfffffff4
);
const
Color
hoverOverlayColor
=
Color
(
0xfffffff5
);
const
Color
hoverOverlayColor
=
Color
(
0xfffffff5
);
const
double
splashRadius
=
1.0
;
const
double
splashRadius
=
1.0
;
const
Icon
icon1
=
Icon
(
Icons
.
check
);
const
Icon
icon2
=
Icon
(
Icons
.
close
);
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
final
ThemeData
themeData
=
ThemeData
(
return
MaterialApp
(
useMaterial3:
true
,
theme:
ThemeData
(
switchTheme:
SwitchThemeData
(
switchTheme:
SwitchThemeData
(
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
...
@@ -110,8 +115,18 @@ void main() {
...
@@ -110,8 +115,18 @@ void main() {
return
null
;
return
null
;
}),
}),
splashRadius:
splashRadius
,
splashRadius:
splashRadius
,
thumbIcon:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
icon1
;
}
return
icon2
;
}),
),
),
),
);
final
bool
material3
=
themeData
.
useMaterial3
;
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Scaffold
(
home:
Scaffold
(
body:
Switch
(
body:
Switch
(
dragStartBehavior:
DragStartBehavior
.
down
,
dragStartBehavior:
DragStartBehavior
.
down
,
...
@@ -128,27 +143,39 @@ void main() {
...
@@ -128,27 +143,39 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
themeData
.
colorScheme
.
outline
)
..
circle
(
color:
defaultThumbColor
)
..
paragraph
()
)
:
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
defaultTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
defaultThumbColor
),
..
circle
(
color:
defaultThumbColor
)
)
);
);
// Size from MaterialTapTargetSize.shrinkWrap.
// Size from MaterialTapTargetSize.shrinkWrap.
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
const
Size
(
59.0
,
40.0
));
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
material3
?
const
Size
(
60.0
,
40.0
)
:
const
Size
(
59.0
,
40.0
));
// Selected switch.
// Selected switch.
await
tester
.
pumpWidget
(
buildSwitch
(
selected:
true
));
await
tester
.
pumpWidget
(
buildSwitch
(
selected:
true
));
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
circle
(
color:
selectedThumbColor
)..
paragraph
())
:
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
rrect
(
color:
selectedTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
selectedThumbColor
)
,
..
circle
(
color:
selectedThumbColor
)
)
);
);
// Switch with hover.
// Switch with hover.
...
@@ -187,9 +214,7 @@ void main() {
...
@@ -187,9 +214,7 @@ void main() {
const
Color
hoverColor
=
Color
(
0xffffff5f
);
const
Color
hoverColor
=
Color
(
0xffffff5f
);
const
double
splashRadius
=
2.0
;
const
double
splashRadius
=
2.0
;
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
final
ThemeData
themeData
=
ThemeData
(
return
MaterialApp
(
theme:
ThemeData
(
switchTheme:
SwitchThemeData
(
switchTheme:
SwitchThemeData
(
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
...
@@ -215,8 +240,19 @@ void main() {
...
@@ -215,8 +240,19 @@ void main() {
return
null
;
return
null
;
}),
}),
splashRadius:
themeSplashRadius
,
splashRadius:
themeSplashRadius
,
thumbIcon:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
null
;
}
return
null
;
}),
),
),
),
);
final
bool
material3
=
themeData
.
useMaterial3
;
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Scaffold
(
home:
Scaffold
(
body:
Switch
(
body:
Switch
(
value:
selected
,
value:
selected
,
...
@@ -239,6 +275,12 @@ void main() {
...
@@ -239,6 +275,12 @@ void main() {
focusColor:
focusColor
,
focusColor:
focusColor
,
hoverColor:
hoverColor
,
hoverColor:
hoverColor
,
splashRadius:
splashRadius
,
splashRadius:
splashRadius
,
thumbIcon:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
const
Icon
(
Icons
.
add
);
}
return
const
Icon
(
Icons
.
access_alarm
);
}),
),
),
),
),
);
);
...
@@ -249,27 +291,36 @@ void main() {
...
@@ -249,27 +291,36 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
themeData
.
colorScheme
.
outline
)
..
circle
(
color:
defaultThumbColor
)..
paragraph
(
offset:
const
Offset
(
12
,
16
)))
:
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
defaultTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
defaultThumbColor
)
,
..
circle
(
color:
defaultThumbColor
)
)
);
);
// Size from MaterialTapTargetSize.shrinkWrap.
// Size from MaterialTapTargetSize.shrinkWrap.
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
const
Size
(
59.0
,
40.0
));
expect
(
tester
.
getSize
(
find
.
byType
(
Switch
)),
material3
?
const
Size
(
60.0
,
40.0
)
:
const
Size
(
59.0
,
40.0
));
// Selected switch.
// Selected switch.
await
tester
.
pumpWidget
(
buildSwitch
(
selected:
true
));
await
tester
.
pumpWidget
(
buildSwitch
(
selected:
true
));
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
circle
(
color:
selectedThumbColor
))
:
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
rrect
(
color:
selectedTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
selectedThumbColor
)
,
..
circle
(
color:
selectedThumbColor
)
)
);
);
// Switch with hover.
// Switch with hover.
...
@@ -298,9 +349,7 @@ void main() {
...
@@ -298,9 +349,7 @@ void main() {
const
Color
defaultTrackColor
=
Color
(
0xffffff2f
);
const
Color
defaultTrackColor
=
Color
(
0xffffff2f
);
const
Color
selectedTrackColor
=
Color
(
0xffffff3f
);
const
Color
selectedTrackColor
=
Color
(
0xffffff3f
);
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
final
ThemeData
themeData
=
ThemeData
(
return
MaterialApp
(
theme:
ThemeData
(
switchTheme:
SwitchThemeData
(
switchTheme:
SwitchThemeData
(
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
thumbColor:
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
...
@@ -315,7 +364,12 @@ void main() {
...
@@ -315,7 +364,12 @@ void main() {
return
themeDefaultTrackColor
;
return
themeDefaultTrackColor
;
}),
}),
),
),
),
);
final
bool
material3
=
themeData
.
useMaterial3
;
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Scaffold
(
home:
Scaffold
(
body:
Switch
(
body:
Switch
(
value:
selected
,
value:
selected
,
...
@@ -335,12 +389,17 @@ void main() {
...
@@ -335,12 +389,17 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
themeData
.
colorScheme
.
outline
)
..
circle
(
color:
defaultThumbColor
))
:
(
paints
..
rrect
(
color:
defaultTrackColor
)
..
rrect
(
color:
defaultTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
defaultThumbColor
),
..
circle
(
color:
defaultThumbColor
))
);
);
// Selected switch.
// Selected switch.
...
@@ -348,12 +407,16 @@ void main() {
...
@@ -348,12 +407,16 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
circle
(
color:
selectedThumbColor
))
:
(
paints
..
rrect
(
color:
selectedTrackColor
)
..
rrect
(
color:
selectedTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
selectedThumbColor
)
,
..
circle
(
color:
selectedThumbColor
)
)
);
);
});
});
...
@@ -371,15 +434,17 @@ void main() {
...
@@ -371,15 +434,17 @@ void main() {
return
null
;
return
null
;
}
}
const
double
splashRadius
=
24.0
;
const
double
splashRadius
=
24.0
;
final
ThemeData
themeData
=
ThemeData
(
Widget
buildSwitch
({
required
bool
active
})
{
return
MaterialApp
(
theme:
ThemeData
(
switchTheme:
SwitchThemeData
(
switchTheme:
SwitchThemeData
(
overlayColor:
MaterialStateProperty
.
resolveWith
(
getOverlayColor
),
overlayColor:
MaterialStateProperty
.
resolveWith
(
getOverlayColor
),
splashRadius:
splashRadius
,
splashRadius:
splashRadius
,
),
),
),
);
final
bool
material3
=
themeData
.
useMaterial3
;
Widget
buildSwitch
({
required
bool
active
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Scaffold
(
home:
Scaffold
(
body:
Switch
(
body:
Switch
(
value:
active
,
value:
active
,
...
@@ -395,12 +460,20 @@ void main() {
...
@@ -395,12 +460,20 @@ void main() {
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
((
paints
..
rrect
()
..
rrect
()
..
rrect
())
..
circle
(
..
circle
(
color:
inactivePressedOverlayColor
,
color:
inactivePressedOverlayColor
,
radius:
splashRadius
,
radius:
splashRadius
,
),
))
:
(
paints
..
rrect
()
..
circle
(
color:
inactivePressedOverlayColor
,
radius:
splashRadius
,
)),
reason:
'Inactive pressed Switch should have overlay color:
$inactivePressedOverlayColor
'
,
reason:
'Inactive pressed Switch should have overlay color:
$inactivePressedOverlayColor
'
,
);
);
...
@@ -426,14 +499,16 @@ void main() {
...
@@ -426,14 +499,16 @@ void main() {
const
Color
localThemeThumbColor
=
Color
(
0xffff0000
);
const
Color
localThemeThumbColor
=
Color
(
0xffff0000
);
const
Color
localThemeTrackColor
=
Color
(
0xffff0000
);
const
Color
localThemeTrackColor
=
Color
(
0xffff0000
);
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
final
ThemeData
themeData
=
ThemeData
(
return
MaterialApp
(
theme:
ThemeData
(
switchTheme:
const
SwitchThemeData
(
switchTheme:
const
SwitchThemeData
(
thumbColor:
MaterialStatePropertyAll
<
Color
>(
globalThemeThumbColor
),
thumbColor:
MaterialStatePropertyAll
<
Color
>(
globalThemeThumbColor
),
trackColor:
MaterialStatePropertyAll
<
Color
>(
globalThemeTrackColor
),
trackColor:
MaterialStatePropertyAll
<
Color
>(
globalThemeTrackColor
),
),
),
),
);
final
bool
material3
=
themeData
.
useMaterial3
;
Widget
buildSwitch
({
bool
selected
=
false
,
bool
autofocus
=
false
})
{
return
MaterialApp
(
theme:
themeData
,
home:
Scaffold
(
home:
Scaffold
(
body:
SwitchTheme
(
body:
SwitchTheme
(
data:
const
SwitchThemeData
(
data:
const
SwitchThemeData
(
...
@@ -454,12 +529,16 @@ void main() {
...
@@ -454,12 +529,16 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
pumpAndSettle
();
expect
(
expect
(
_getSwitchMaterial
(
tester
),
_getSwitchMaterial
(
tester
),
paints
material3
?
(
paints
..
rrect
(
color:
localThemeTrackColor
)
..
circle
(
color:
localThemeThumbColor
))
:
(
paints
..
rrect
(
color:
localThemeTrackColor
)
..
rrect
(
color:
localThemeTrackColor
)
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
()
..
circle
(
color:
localThemeThumbColor
)
,
..
circle
(
color:
localThemeThumbColor
)
)
);
);
});
});
}
}
...
...
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