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
98eac3f1
Unverified
Commit
98eac3f1
authored
Sep 08, 2022
by
Qun Cheng
Committed by
GitHub
Sep 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrated `Checkbox` to Material 3 - Added Error State (#111153)
parent
4d3c1224
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
209 additions
and
67 deletions
+209
-67
checkbox_template.dart
dev/tools/gen_defaults/lib/checkbox_template.dart
+17
-30
checkbox.1.dart
examples/api/lib/material/checkbox/checkbox.1.dart
+74
-0
checkbox.dart
packages/flutter/lib/src/material/checkbox.dart
+44
-37
theme_data.dart
packages/flutter/lib/src/material/theme_data.dart
+1
-0
checkbox_test.dart
packages/flutter/test/material/checkbox_test.dart
+73
-0
No files found.
dev/tools/gen_defaults/lib/checkbox_template.dart
View file @
98eac3f1
...
...
@@ -23,32 +23,14 @@ class _${blockName}DefaultsM3 extends CheckboxThemeData {
MaterialStateProperty<Color> get fillColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return
${componentColor('md.comp.checkbox.selected.disabled.container')}
;
}
return
${componentColor('md.comp.checkbox.unselected.
disabled.outline')}
.withOpacity(
${opacity('md.comp.checkbox.unselected.disabled.container.opacity')}
)
;
return
${componentColor('md.comp.checkbox.selected.disabled.container')}
;
}
if (states.contains(MaterialState.error)) {
return
${componentColor('md.comp.checkbox.unselected.
error.outline')}
;
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.checkbox.selected.pressed.container')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.checkbox.selected.hover.container')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.checkbox.selected.focus.container')}
;
}
return
${componentColor('md.comp.checkbox.selected.container')}
;
}
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.checkbox.unselected.pressed.outline')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.checkbox.unselected.hover.outline')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.checkbox.unselected.focus.outline')}
;
}
return
${componentColor('md.comp.checkbox.unselected.outline')}
;
});
}
...
...
@@ -63,14 +45,8 @@ class _${blockName}DefaultsM3 extends CheckboxThemeData {
return Colors.transparent; // No icons available when the checkbox is unselected.
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.checkbox.selected.pressed.icon')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.checkbox.selected.hover.icon')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.checkbox.selected.focus.icon')}
;
if (states.contains(MaterialState.error)) {
return
${componentColor('md.comp.checkbox.selected.error.icon')}
;
}
return
${componentColor('md.comp.checkbox.selected.icon')}
;
}
...
...
@@ -81,6 +57,17 @@ class _${blockName}DefaultsM3 extends CheckboxThemeData {
@override
MaterialStateProperty<Color> get overlayColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.error)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.checkbox.error.pressed.state-layer')}
;
}
if (states.contains(MaterialState.hovered)) {
return
${componentColor('md.comp.checkbox.error.hover.state-layer')}
;
}
if (states.contains(MaterialState.focused)) {
return
${componentColor('md.comp.checkbox.error.focus.state-layer')}
.withOpacity(0.12);
}
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return
${componentColor('md.comp.checkbox.selected.pressed.state-layer')}
;
...
...
examples/api/lib/material/checkbox/checkbox.1.dart
0 → 100644
View file @
98eac3f1
// 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 M3 Checkbox with error state
import
'package:flutter/material.dart'
;
void
main
(
)
=>
runApp
(
const
MyApp
());
class
MyApp
extends
StatelessWidget
{
const
MyApp
({
super
.
key
});
static
const
String
_title
=
'Flutter Code Sample'
;
@override
Widget
build
(
BuildContext
context
)
{
return
MaterialApp
(
theme:
ThemeData
(
useMaterial3:
true
,
colorSchemeSeed:
const
Color
(
0xff6750a4
)),
title:
_title
,
home:
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
_title
)),
body:
const
Center
(
child:
MyStatefulWidget
(),
),
),
);
}
}
class
MyStatefulWidget
extends
StatefulWidget
{
const
MyStatefulWidget
({
super
.
key
});
@override
State
<
MyStatefulWidget
>
createState
()
=>
_MyStatefulWidgetState
();
}
class
_MyStatefulWidgetState
extends
State
<
MyStatefulWidget
>
{
bool
?
isChecked
=
true
;
@override
Widget
build
(
BuildContext
context
)
{
return
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
Checkbox
(
tristate:
true
,
value:
isChecked
,
onChanged:
(
bool
?
value
)
{
setState
(()
{
isChecked
=
value
;
});
},
),
Checkbox
(
isError:
true
,
tristate:
true
,
value:
isChecked
,
onChanged:
(
bool
?
value
)
{
setState
(()
{
isChecked
=
value
;
});
},
),
Checkbox
(
isError:
true
,
tristate:
true
,
value:
isChecked
,
onChanged:
null
,
),
],
);
}
}
packages/flutter/lib/src/material/checkbox.dart
View file @
98eac3f1
...
...
@@ -87,6 +87,7 @@ class Checkbox extends StatefulWidget {
this
.
autofocus
=
false
,
this
.
shape
,
this
.
side
,
this
.
isError
=
false
,
})
:
assert
(
tristate
!=
null
),
assert
(
tristate
||
value
!=
null
),
assert
(
autofocus
!=
null
);
...
...
@@ -332,6 +333,14 @@ class Checkbox extends StatefulWidget {
/// will be width 2.
final
BorderSide
?
side
;
/// True if this checkbox wants to show an error state.
///
/// The checkbox will have different default container color and check color when
/// this is true. This is only used when [ThemeData.useMaterial3] is set to true.
///
/// Must not be null. Defaults to false.
final
bool
isError
;
/// The width of a checkbox widget.
static
const
double
width
=
18.0
;
...
...
@@ -427,8 +436,9 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
// Colors need to be resolved in selected and non selected states separately
// so that they can be lerped between.
final
Set
<
MaterialState
>
activeStates
=
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
states
..
remove
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
errorState
=
states
..
add
(
MaterialState
.
error
);
final
Set
<
MaterialState
>
activeStates
=
widget
.
isError
?
(
errorState
..
add
(
MaterialState
.
selected
))
:
states
..
add
(
MaterialState
.
selected
);
final
Set
<
MaterialState
>
inactiveStates
=
widget
.
isError
?
(
errorState
..
remove
(
MaterialState
.
selected
))
:
states
..
remove
(
MaterialState
.
selected
);
final
Color
?
activeColor
=
widget
.
fillColor
?.
resolve
(
activeStates
)
??
_widgetFillColor
.
resolve
(
activeStates
)
??
checkboxTheme
.
fillColor
?.
resolve
(
activeStates
);
...
...
@@ -440,14 +450,14 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
final
Color
effectiveInactiveColor
=
inactiveColor
??
defaults
.
fillColor
!.
resolve
(
inactiveStates
)!;
final
Set
<
MaterialState
>
focusedStates
=
states
..
add
(
MaterialState
.
focused
);
final
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
final
Set
<
MaterialState
>
focusedStates
=
widget
.
isError
?
(
errorState
..
add
(
MaterialState
.
focused
))
:
states
..
add
(
MaterialState
.
focused
);
Color
effectiveFocusOverlayColor
=
widget
.
overlayColor
?.
resolve
(
focusedStates
)
??
widget
.
focusColor
??
checkboxTheme
.
overlayColor
?.
resolve
(
focusedStates
)
??
defaults
.
overlayColor
!.
resolve
(
focusedStates
)!;
final
Set
<
MaterialState
>
hoveredStates
=
states
..
add
(
MaterialState
.
hovered
);
final
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
final
Set
<
MaterialState
>
hoveredStates
=
widget
.
isError
?
(
errorState
..
add
(
MaterialState
.
hovered
))
:
states
..
add
(
MaterialState
.
hovered
);
Color
effectiveHoverOverlayColor
=
widget
.
overlayColor
?.
resolve
(
hoveredStates
)
??
widget
.
hoverColor
??
checkboxTheme
.
overlayColor
?.
resolve
(
hoveredStates
)
??
defaults
.
overlayColor
!.
resolve
(
hoveredStates
)!;
...
...
@@ -464,9 +474,19 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
??
inactiveColor
?.
withAlpha
(
kRadialReactionAlpha
)
??
defaults
.
overlayColor
!.
resolve
(
inactivePressedStates
)!;
if
(
downPosition
!=
null
)
{
effectiveHoverOverlayColor
=
states
.
contains
(
MaterialState
.
selected
)
?
effectiveActivePressedOverlayColor
:
effectiveInactivePressedOverlayColor
;
effectiveFocusOverlayColor
=
states
.
contains
(
MaterialState
.
selected
)
?
effectiveActivePressedOverlayColor
:
effectiveInactivePressedOverlayColor
;
}
final
Set
<
MaterialState
>
checkStates
=
widget
.
isError
?
(
states
..
add
(
MaterialState
.
error
))
:
states
;
final
Color
effectiveCheckColor
=
widget
.
checkColor
??
checkboxTheme
.
checkColor
?.
resolve
(
s
tates
)
??
defaults
.
checkColor
!.
resolve
(
s
tates
)!;
??
checkboxTheme
.
checkColor
?.
resolve
(
checkS
tates
)
??
defaults
.
checkColor
!.
resolve
(
checkS
tates
)!;
final
double
effectiveSplashRadius
=
widget
.
splashRadius
??
checkboxTheme
.
splashRadius
...
...
@@ -758,32 +778,14 @@ class _CheckboxDefaultsM3 extends CheckboxThemeData {
MaterialStateProperty
<
Color
>
get
fillColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.38
);
}
return
_colors
.
onSurface
.
withOpacity
(
0.38
);
}
if
(
states
.
contains
(
MaterialState
.
error
))
{
return
_colors
.
error
;
}
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
.
onSurface
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
onSurface
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
onSurface
;
}
return
_colors
.
onSurface
;
});
}
...
...
@@ -798,14 +800,8 @@ class _CheckboxDefaultsM3 extends CheckboxThemeData {
return
Colors
.
transparent
;
// No icons available when the checkbox is unselected.
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
onPrimary
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
onPrimary
;
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
onPrimary
;
if
(
states
.
contains
(
MaterialState
.
error
))
{
return
_colors
.
onError
;
}
return
_colors
.
onPrimary
;
}
...
...
@@ -816,6 +812,17 @@ class _CheckboxDefaultsM3 extends CheckboxThemeData {
@override
MaterialStateProperty
<
Color
>
get
overlayColor
{
return
MaterialStateProperty
.
resolveWith
((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
error
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
error
.
withOpacity
(
0.12
);
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
_colors
.
error
.
withOpacity
(
0.08
);
}
if
(
states
.
contains
(
MaterialState
.
focused
))
{
return
_colors
.
error
.
withOpacity
(
0.12
);
}
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
return
_colors
.
onSurface
.
withOpacity
(
0.12
);
...
...
packages/flutter/lib/src/material/theme_data.dart
View file @
98eac3f1
...
...
@@ -1261,6 +1261,7 @@ class ThemeData with Diagnosticable {
/// - [ActionChip] (used for Assist and Suggestion chips),
/// - [FilterChip], [ChoiceChip] (used for single selection filter chips),
/// - [InputChip]
/// * Checkbox: [Checkbox]
/// * Dialogs: [Dialog], [AlertDialog]
/// * Lists: [ListTile]
/// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar])
...
...
packages/flutter/test/material/checkbox_test.dart
View file @
98eac3f1
...
...
@@ -1088,6 +1088,7 @@ void main() {
reason:
'Default active pressed Checkbox should have overlay color from default fillColor'
,
);
await
tester
.
pumpWidget
(
Container
());
// reset test
await
tester
.
pumpWidget
(
buildCheckbox
(
focused:
true
));
await
tester
.
pumpAndSettle
();
...
...
@@ -1220,6 +1221,7 @@ void main() {
reason:
'Active pressed Checkbox should have overlay color:
$activePressedOverlayColor
'
,
);
await
tester
.
pumpWidget
(
Container
());
// reset test
await
tester
.
pumpWidget
(
buildCheckbox
(
focused:
true
));
await
tester
.
pumpAndSettle
();
...
...
@@ -1550,6 +1552,77 @@ void main() {
await
tester
.
pump
(
const
Duration
(
milliseconds:
10
));
expect
(
find
.
text
(
tapTooltip
),
findsOneWidget
);
});
testWidgets
(
'Checkbox has default error color when isError is set to true - M3'
,
(
WidgetTester
tester
)
async
{
final
FocusNode
focusNode
=
FocusNode
(
debugLabel:
'Checkbox'
);
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
bool
?
value
=
true
;
Widget
buildApp
({
bool
autoFocus
=
true
})
{
return
MaterialApp
(
theme:
ThemeData
(
useMaterial3:
true
),
home:
Material
(
child:
Center
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Checkbox
(
isError:
true
,
value:
value
,
onChanged:
(
bool
?
newValue
)
{
setState
(()
{
value
=
newValue
;
});
},
autofocus:
autoFocus
,
focusNode:
focusNode
,
);
}),
),
),
);
}
// Focused
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isTrue
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
paints
..
circle
(
color:
theme
.
colorScheme
.
error
.
withOpacity
(
0.12
))..
path
(
color:
theme
.
colorScheme
.
error
)..
path
(
color:
theme
.
colorScheme
.
onError
)
);
// Default color
await
tester
.
pumpWidget
(
Container
());
await
tester
.
pumpWidget
(
buildApp
(
autoFocus:
false
));
await
tester
.
pumpAndSettle
();
expect
(
focusNode
.
hasPrimaryFocus
,
isFalse
);
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
paints
..
path
(
color:
theme
.
colorScheme
.
error
)..
path
(
color:
theme
.
colorScheme
.
onError
)
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Checkbox
)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
paints
..
circle
(
color:
theme
.
colorScheme
.
error
.
withOpacity
(
0.08
))
..
path
(
color:
theme
.
colorScheme
.
error
)
);
// Start pressing
final
TestGesture
gestureLongPress
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
byType
(
Checkbox
)));
await
tester
.
pump
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Checkbox
))),
paints
..
circle
(
color:
theme
.
colorScheme
.
error
.
withOpacity
(
0.12
))
..
path
(
color:
theme
.
colorScheme
.
error
)
);
await
gestureLongPress
.
up
();
await
tester
.
pump
();
});
}
class
_SelectedGrabMouseCursor
extends
MaterialStateMouseCursor
{
...
...
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