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
51227a9a
Unverified
Commit
51227a9a
authored
Feb 08, 2023
by
Qun Cheng
Committed by
GitHub
Feb 08, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add missing parameters to `RadioListTile` (#120117)
parent
3a514175
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
486 additions
and
2 deletions
+486
-2
radio.dart
packages/flutter/lib/src/material/radio.dart
+3
-1
radio_list_tile.dart
packages/flutter/lib/src/material/radio_list_tile.dart
+65
-1
radio_list_tile_test.dart
packages/flutter/test/material/radio_list_tile_test.dart
+418
-0
No files found.
packages/flutter/lib/src/material/radio.dart
View file @
51227a9a
...
...
@@ -264,10 +264,12 @@ class Radio<T> extends StatefulWidget {
/// [ThemeData.focusColor] is used.
final
Color
?
focusColor
;
/// {@template flutter.material.radio.hoverColor}
/// The color for the radio's [Material] when a pointer is hovering over it.
///
/// If [overlayColor] returns a non-null color in the [MaterialState.hovered]
/// state, it will be used instead.
/// {@endtemplate}
///
/// If null, then the value of [RadioThemeData.overlayColor] is used in the
/// hovered state. If that is also null, then the value of
...
...
@@ -275,7 +277,7 @@ class Radio<T> extends StatefulWidget {
final
Color
?
hoverColor
;
/// {@template flutter.material.radio.overlayColor}
/// The color for the
checkbox
's [Material].
/// The color for the
radio
's [Material].
///
/// Resolves in the following states:
/// * [MaterialState.pressed].
...
...
packages/flutter/lib/src/material/radio_list_tile.dart
View file @
51227a9a
...
...
@@ -162,8 +162,14 @@ class RadioListTile<T> extends StatelessWidget {
required
this
.
value
,
required
this
.
groupValue
,
required
this
.
onChanged
,
this
.
mouseCursor
,
this
.
toggleable
=
false
,
this
.
activeColor
,
this
.
fillColor
,
this
.
hoverColor
,
this
.
overlayColor
,
this
.
splashRadius
,
this
.
materialTapTargetSize
,
this
.
title
,
this
.
subtitle
,
this
.
isThreeLine
=
false
,
...
...
@@ -220,6 +226,20 @@ class RadioListTile<T> extends StatelessWidget {
/// ```
final
ValueChanged
<
T
?>?
onChanged
;
/// The cursor for a mouse pointer when it enters or is hovering over the
/// widget.
///
/// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
///
/// * [MaterialState.selected].
/// * [MaterialState.hovered].
/// * [MaterialState.disabled].
///
/// If null, then the value of [RadioThemeData.mouseCursor] is used.
/// If that is also null, then [MaterialStateMouseCursor.clickable] is used.
final
MouseCursor
?
mouseCursor
;
/// Set to true if this radio list tile is allowed to be returned to an
/// indeterminate state by selecting it again when selected.
///
...
...
@@ -250,6 +270,45 @@ class RadioListTile<T> extends StatelessWidget {
/// Defaults to [ColorScheme.secondary] of the current [Theme].
final
Color
?
activeColor
;
/// The color that fills the radio button.
///
/// Resolves in the following states:
/// * [MaterialState.selected].
/// * [MaterialState.hovered].
/// * [MaterialState.disabled].
///
/// If null, then the value of [activeColor] is used in the selected state. If
/// that is also null, then the value of [RadioThemeData.fillColor] is used.
/// If that is also null, then the default value is used.
final
MaterialStateProperty
<
Color
?>?
fillColor
;
/// {@macro flutter.material.radio.materialTapTargetSize}
///
/// Defaults to [MaterialTapTargetSize.shrinkWrap].
final
MaterialTapTargetSize
?
materialTapTargetSize
;
/// {@macro flutter.material.radio.hoverColor}
final
Color
?
hoverColor
;
/// The color for the radio's [Material].
///
/// Resolves in the following states:
/// * [MaterialState.pressed].
/// * [MaterialState.selected].
/// * [MaterialState.hovered].
///
/// If null, then the value of [activeColor] with alpha [kRadialReactionAlpha]
/// and [hoverColor] is used in the pressed and hovered state. If that is also
/// null, the value of [SwitchThemeData.overlayColor] is used. If that is
/// also null, then the default value is used in the pressed and hovered state.
final
MaterialStateProperty
<
Color
?>?
overlayColor
;
/// {@macro flutter.material.radio.splashRadius}
///
/// If null, then the value of [RadioThemeData.splashRadius] is used. If that
/// is also null, then [kRadialReactionRadius] is used.
final
double
?
splashRadius
;
/// The primary content of the list tile.
///
/// Typically a [Text] widget.
...
...
@@ -341,8 +400,13 @@ class RadioListTile<T> extends StatelessWidget {
onChanged:
onChanged
,
toggleable:
toggleable
,
activeColor:
activeColor
,
materialTapTargetSize:
MaterialTapTargetSize
.
shrinkWrap
,
materialTapTargetSize:
materialTapTargetSize
??
MaterialTapTargetSize
.
shrinkWrap
,
autofocus:
autofocus
,
fillColor:
fillColor
,
mouseCursor:
mouseCursor
,
hoverColor:
hoverColor
,
overlayColor:
overlayColor
,
splashRadius:
splashRadius
,
);
Widget
?
leading
,
trailing
;
switch
(
controlAffinity
)
{
...
...
packages/flutter/test/material/radio_list_tile_test.dart
View file @
51227a9a
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
...
...
@@ -823,6 +824,423 @@ void main() {
expect
(
node
.
hasFocus
,
isFalse
);
});
testWidgets
(
'Radio changes mouse cursor when hovered'
,
(
WidgetTester
tester
)
async
{
// Test Radio() constructor
await
tester
.
pumpWidget
(
wrap
(
child:
MouseRegion
(
cursor:
SystemMouseCursors
.
forbidden
,
child:
RadioListTile
<
int
>(
mouseCursor:
SystemMouseCursors
.
text
,
value:
1
,
onChanged:
(
int
?
v
)
{},
groupValue:
2
,
),
)),
);
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
,
pointer:
1
);
await
gesture
.
addPointer
(
location:
tester
.
getCenter
(
find
.
byType
(
Radio
<
int
>)));
await
tester
.
pump
();
expect
(
RendererBinding
.
instance
.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
text
);
// Test default cursor
await
tester
.
pumpWidget
(
wrap
(
child:
MouseRegion
(
cursor:
SystemMouseCursors
.
forbidden
,
child:
RadioListTile
<
int
>(
value:
1
,
onChanged:
(
int
?
v
)
{},
groupValue:
2
,
),
)),
);
expect
(
RendererBinding
.
instance
.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
click
);
// Test default cursor when disabled
await
tester
.
pumpWidget
(
wrap
(
child:
const
MouseRegion
(
cursor:
SystemMouseCursors
.
forbidden
,
child:
RadioListTile
<
int
>(
value:
1
,
onChanged:
null
,
groupValue:
2
,
),
),
),);
expect
(
RendererBinding
.
instance
.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
basic
);
});
testWidgets
(
'RadioListTile respects fillColor in enabled/disabled states'
,
(
WidgetTester
tester
)
async
{
const
Color
activeEnabledFillColor
=
Color
(
0xFF000001
);
const
Color
activeDisabledFillColor
=
Color
(
0xFF000002
);
const
Color
inactiveEnabledFillColor
=
Color
(
0xFF000003
);
const
Color
inactiveDisabledFillColor
=
Color
(
0xFF000004
);
Color
getFillColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeDisabledFillColor
;
}
return
inactiveDisabledFillColor
;
}
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activeEnabledFillColor
;
}
return
inactiveEnabledFillColor
;
}
final
MaterialStateProperty
<
Color
>
fillColor
=
MaterialStateColor
.
resolveWith
(
getFillColor
);
int
?
groupValue
=
0
;
Widget
buildApp
({
required
bool
enabled
})
{
return
wrap
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
RadioListTile
<
int
>(
value:
0
,
fillColor:
fillColor
,
onChanged:
enabled
?
(
int
?
newValue
)
{
setState
(()
{
groupValue
=
newValue
;
});
}
:
null
,
groupValue:
groupValue
,
);
})
);
}
await
tester
.
pumpWidget
(
buildApp
(
enabled:
true
));
// Selected and enabled.
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
activeEnabledFillColor
)
..
circle
(
color:
activeEnabledFillColor
),
);
// Check when the radio isn't selected.
groupValue
=
1
;
await
tester
.
pumpWidget
(
buildApp
(
enabled:
true
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
inactiveEnabledFillColor
,
style:
PaintingStyle
.
stroke
,
strokeWidth:
2.0
),
);
// Check when the radio is selected, but disabled.
groupValue
=
0
;
await
tester
.
pumpWidget
(
buildApp
(
enabled:
false
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
activeDisabledFillColor
)
..
circle
(
color:
activeDisabledFillColor
),
);
// Check when the radio is unselected and disabled.
groupValue
=
1
;
await
tester
.
pumpWidget
(
buildApp
(
enabled:
false
));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
inactiveDisabledFillColor
,
style:
PaintingStyle
.
stroke
,
strokeWidth:
2.0
),
);
});
testWidgets
(
'RadioListTile respects fillColor in hovered state'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
const
Color
hoveredFillColor
=
Color
(
0xFF000001
);
Color
getFillColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
hoveredFillColor
;
}
return
Colors
.
transparent
;
}
final
MaterialStateProperty
<
Color
>
fillColor
=
MaterialStateColor
.
resolveWith
(
getFillColor
);
int
?
groupValue
=
0
;
Widget
buildApp
()
{
return
wrap
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
RadioListTile
<
int
>(
value:
0
,
fillColor:
fillColor
,
onChanged:
(
int
?
newValue
)
{
setState
(()
{
groupValue
=
newValue
;
});
},
groupValue:
groupValue
,
);
}),
);
}
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Radio
<
int
>)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()..
circle
()
..
circle
(
color:
hoveredFillColor
),
);
});
testWidgets
(
'RadioListTile respects hoverColor'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
int
?
groupValue
=
0
;
final
Color
?
hoverColor
=
Colors
.
orange
[
500
];
Widget
buildApp
({
bool
enabled
=
true
})
{
return
wrap
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
RadioListTile
<
int
>(
value:
0
,
onChanged:
enabled
?
(
int
?
newValue
)
{
setState
(()
{
groupValue
=
newValue
;
});
}
:
null
,
hoverColor:
hoverColor
,
groupValue:
groupValue
,
);
}),
);
}
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
const
Color
(
0xff2196f3
))
..
circle
(
color:
const
Color
(
0xff2196f3
)),
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Radio
<
int
>)));
// Check when the radio isn't selected.
groupValue
=
1
;
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
hoverColor
)
);
// Check when the radio is selected, but disabled.
groupValue
=
0
;
await
tester
.
pumpWidget
(
buildApp
(
enabled:
false
));
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
int
>))),
paints
..
rect
()
..
circle
(
color:
const
Color
(
0x61000000
))
..
circle
(
color:
const
Color
(
0x61000000
)),
);
});
testWidgets
(
'RadioListTile respects overlayColor in active/pressed/hovered states'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
const
Color
fillColor
=
Color
(
0xFF000000
);
const
Color
activePressedOverlayColor
=
Color
(
0xFF000001
);
const
Color
inactivePressedOverlayColor
=
Color
(
0xFF000002
);
const
Color
hoverOverlayColor
=
Color
(
0xFF000003
);
const
Color
hoverColor
=
Color
(
0xFF000005
);
Color
?
getOverlayColor
(
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
pressed
))
{
if
(
states
.
contains
(
MaterialState
.
selected
))
{
return
activePressedOverlayColor
;
}
return
inactivePressedOverlayColor
;
}
if
(
states
.
contains
(
MaterialState
.
hovered
))
{
return
hoverOverlayColor
;
}
return
null
;
}
Widget
buildRadio
({
bool
active
=
false
,
bool
useOverlay
=
true
})
{
return
wrap
(
child:
RadioListTile
<
bool
>(
value:
active
,
groupValue:
true
,
onChanged:
(
_
)
{
},
fillColor:
const
MaterialStatePropertyAll
<
Color
>(
fillColor
),
overlayColor:
useOverlay
?
MaterialStateProperty
.
resolveWith
(
getOverlayColor
)
:
null
,
hoverColor:
hoverColor
,
),
);
}
await
tester
.
pumpWidget
(
buildRadio
(
useOverlay:
false
));
await
tester
.
press
(
find
.
byType
(
Radio
<
bool
>));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
bool
>))),
paints
..
circle
()
..
circle
(
color:
fillColor
.
withAlpha
(
kRadialReactionAlpha
),
radius:
20
,
),
reason:
'Default inactive pressed Radio should have overlay color from fillColor'
,
);
await
tester
.
pumpWidget
(
buildRadio
(
active:
true
,
useOverlay:
false
));
await
tester
.
press
(
find
.
byType
(
Radio
<
bool
>));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
bool
>))),
paints
..
circle
()
..
circle
(
color:
fillColor
.
withAlpha
(
kRadialReactionAlpha
),
radius:
20
,
),
reason:
'Default active pressed Radio should have overlay color from fillColor'
,
);
await
tester
.
pumpWidget
(
buildRadio
());
await
tester
.
press
(
find
.
byType
(
Radio
<
bool
>));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
bool
>))),
paints
..
circle
()
..
circle
(
color:
inactivePressedOverlayColor
,
radius:
20
,
),
reason:
'Inactive pressed Radio should have overlay color:
$inactivePressedOverlayColor
'
,
);
await
tester
.
pumpWidget
(
buildRadio
(
active:
true
));
await
tester
.
press
(
find
.
byType
(
Radio
<
bool
>));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
bool
>))),
paints
..
circle
()
..
circle
(
color:
activePressedOverlayColor
,
radius:
20
,
),
reason:
'Active pressed Radio should have overlay color:
$activePressedOverlayColor
'
,
);
// Start hovering
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Radio
<
bool
>)));
await
tester
.
pumpAndSettle
();
await
tester
.
pumpWidget
(
Container
());
await
tester
.
pumpWidget
(
buildRadio
());
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byType
(
Radio
<
bool
>))),
paints
..
circle
(
color:
hoverOverlayColor
,
radius:
20
,
),
reason:
'Hovered Radio should use overlay color
$hoverOverlayColor
over
$hoverColor
'
,
);
});
testWidgets
(
'RadioListTile respects splashRadius'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
focusManager
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
const
double
splashRadius
=
30
;
Widget
buildApp
()
{
return
wrap
(
child:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
RadioListTile
<
int
>(
value:
0
,
onChanged:
(
_
)
{},
hoverColor:
Colors
.
orange
[
500
],
groupValue:
0
,
splashRadius:
splashRadius
,
);
}),
);
}
await
tester
.
pumpWidget
(
buildApp
());
await
tester
.
pumpAndSettle
();
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byType
(
Radio
<
int
>)));
await
tester
.
pumpAndSettle
();
expect
(
Material
.
of
(
tester
.
element
(
find
.
byWidgetPredicate
((
Widget
widget
)
=>
widget
is
Radio
<
int
>),
)),
paints
..
circle
(
color:
Colors
.
orange
[
500
],
radius:
splashRadius
),
);
});
testWidgets
(
'Radio respects materialTapTargetSize'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
wrap
(
child:
RadioListTile
<
bool
>(
groupValue:
true
,
value:
true
,
onChanged:
(
bool
?
newValue
)
{
},
)),
);
// default test
expect
(
tester
.
getSize
(
find
.
byType
(
Radio
<
bool
>)),
const
Size
(
40.0
,
40.0
));
await
tester
.
pumpWidget
(
wrap
(
child:
RadioListTile
<
bool
>(
materialTapTargetSize:
MaterialTapTargetSize
.
padded
,
groupValue:
true
,
value:
true
,
onChanged:
(
bool
?
newValue
)
{
},
)),
);
expect
(
tester
.
getSize
(
find
.
byType
(
Radio
<
bool
>)),
const
Size
(
48.0
,
48.0
));
});
group
(
'feedback'
,
()
{
late
FeedbackTester
feedback
;
...
...
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