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
59cf0d22
Unverified
Commit
59cf0d22
authored
Dec 01, 2020
by
xubaolin
Committed by
GitHub
Dec 01, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve the behavior of DropdownButton.disabledHint (#70277)
parent
7477524d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
102 additions
and
25 deletions
+102
-25
dropdown.dart
packages/flutter/lib/src/material/dropdown.dart
+31
-25
dropdown_test.dart
packages/flutter/test/material/dropdown_test.dart
+71
-0
No files found.
packages/flutter/lib/src/material/dropdown.dart
View file @
59cf0d22
...
...
@@ -793,9 +793,14 @@ class DropdownButton<T> extends StatefulWidget {
/// The [items] must have distinct values. If [value] isn't null then it
/// must be equal to one of the [DropdownMenuItem] values. If [items] or
/// [onChanged] is null, the button will be disabled, the down arrow
/// will be greyed out, and the [disabledHint] will be shown (if provided).
/// If [disabledHint] is null and [hint] is non-null, [hint] will instead be
/// shown.
/// will be greyed out.
///
/// If [value] is null and the button is enabled, [hint] will be displayed
/// if it is non-null.
///
/// If [value] is null and the button is disabled, [disabledHint] will be displayed
/// if it is non-null. If [disabledHint] is null, then [hint] will be displayed
/// if it is non-null.
///
/// The [elevation] and [iconSize] arguments must not be null (they both have
/// defaults, so do not need to be specified). The boolean [isDense] and
...
...
@@ -813,7 +818,7 @@ class DropdownButton<T> extends StatefulWidget {
this
.
value
,
this
.
hint
,
this
.
disabledHint
,
required
this
.
onChanged
,
this
.
onChanged
,
this
.
onTap
,
this
.
elevation
=
8
,
this
.
style
,
...
...
@@ -852,29 +857,32 @@ class DropdownButton<T> extends StatefulWidget {
///
/// If the [onChanged] callback is null or the list of items is null
/// then the dropdown button will be disabled, i.e. its arrow will be
/// displayed in grey and it will not respond to input. A disabled button
/// will display the [disabledHint] widget if it is non-null. If
/// [disabledHint] is also null but [hint] is non-null, [hint] will instead
/// be displayed.
/// displayed in grey and it will not respond to input.
final
List
<
DropdownMenuItem
<
T
>>?
items
;
/// The value of the currently selected [DropdownMenuItem].
///
/// If [value] is null and [hint] is non-null, the [hint] widget is
/// displayed as a placeholder for the dropdown button's value.
/// If [value] is null and the button is enabled, [hint] will be displayed
/// if it is non-null.
///
/// If [value] is null and the button is disabled, [disabledHint] will be displayed
/// if it is non-null. If [disabledHint] is null, then [hint] will be displayed
/// if it is non-null.
final
T
?
value
;
/// A placeholder widget that is displayed by the dropdown button.
///
/// If [value] is null, this widget is displayed as a placeholder for
/// the dropdown button's value. This widget is also displayed if the button
/// is disabled ([items] or [onChanged] is null) and [disabledHint] is null.
/// If [value] is null and the dropdown is enabled ([items] and [onChanged] are non-null),
/// this widget is displayed as a placeholder for the dropdown button's value.
///
/// If [value] is null and the dropdown is disabled and [disabledHint] is null,
/// this widget is used as the placeholder.
final
Widget
?
hint
;
/// A
message to show
when the dropdown is disabled.
/// A
preferred placeholder widget that is displayed
when the dropdown is disabled.
///
///
Displayed if [items] or [onChanged] is null. If [hint] is non-null and
///
[disabledHint] is null, the [hint] widget will be displayed instead
.
///
If [value] is null, the dropdown is disabled ([items] or [onChanged] is null),
///
this widget is displayed as a placeholder for the dropdown button's value
.
final
Widget
?
disabledHint
;
/// {@template flutter.material.dropdownButton.onChanged}
...
...
@@ -1160,13 +1168,12 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
}
void
_updateSelectedIndex
()
{
if
(!
_enabled
)
{
if
(
widget
.
value
==
null
||
widget
.
items
==
null
||
widget
.
items
!.
isEmpty
)
{
_selectedIndex
=
null
;
return
;
}
assert
(
widget
.
value
==
null
||
widget
.
items
!.
where
((
DropdownMenuItem
<
T
>
item
)
=>
item
.
value
==
widget
.
value
).
length
==
1
);
_selectedIndex
=
null
;
assert
(
widget
.
items
!.
where
((
DropdownMenuItem
<
T
>
item
)
=>
item
.
value
==
widget
.
value
).
length
==
1
);
for
(
int
itemIndex
=
0
;
itemIndex
<
widget
.
items
!.
length
;
itemIndex
++)
{
if
(
widget
.
items
![
itemIndex
].
value
==
widget
.
value
)
{
_selectedIndex
=
itemIndex
;
...
...
@@ -1307,7 +1314,7 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
// otherwise, no explicit type adding items maybe trigger a crash/failure
// when hint and selectedItemBuilder are provided.
final
List
<
Widget
>
items
=
widget
.
selectedItemBuilder
==
null
?
(
_enabled
?
List
<
Widget
>.
from
(
widget
.
items
!)
:
<
Widget
>[])
?
(
widget
.
items
!=
null
?
List
<
Widget
>.
from
(
widget
.
items
!)
:
<
Widget
>[])
:
List
<
Widget
>.
from
(
widget
.
selectedItemBuilder
!(
context
));
int
?
hintIndex
;
...
...
@@ -1330,15 +1337,14 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
?
_kAlignedButtonPadding
:
_kUnalignedButtonPadding
;
// If value is null (then _selectedIndex is null)
or if disabled
then we
// If value is null (then _selectedIndex is null) then we
// display the hint or nothing at all.
final
int
?
index
=
_enabled
?
(
_selectedIndex
??
hintIndex
)
:
hintIndex
;
final
Widget
innerItemsWidget
;
if
(
items
.
isEmpty
)
{
innerItemsWidget
=
Container
();
}
else
{
innerItemsWidget
=
IndexedStack
(
index:
i
ndex
,
index:
_selectedIndex
??
hintI
ndex
,
alignment:
AlignmentDirectional
.
centerStart
,
children:
widget
.
isDense
?
items
:
items
.
map
((
Widget
item
)
{
return
widget
.
itemHeight
!=
null
...
...
@@ -1443,7 +1449,7 @@ class DropdownButtonFormField<T> extends FormField<T> {
T
?
value
,
Widget
?
hint
,
Widget
?
disabledHint
,
required
this
.
onChanged
,
this
.
onChanged
,
VoidCallback
?
onTap
,
int
elevation
=
8
,
TextStyle
?
style
,
...
...
packages/flutter/test/material/dropdown_test.dart
View file @
59cf0d22
...
...
@@ -1341,6 +1341,77 @@ void main() {
expect
(
enabledHintBox
.
size
,
equals
(
disabledHintBox
.
size
));
});
// Regression test for https://github.com/flutter/flutter/issues/70177
testWidgets
(
'disabledHint behavior test'
,
(
WidgetTester
tester
)
async
{
Widget
build
({
List
<
String
>?
items
,
ValueChanged
<
String
?>?
onChanged
,
String
?
value
,
Widget
?
hint
,
Widget
?
disabledHint
})
=>
buildFrame
(
items:
items
,
onChanged:
onChanged
,
value:
value
,
hint:
hint
,
disabledHint:
disabledHint
,
);
// The selected value should be displayed when the button is disabled.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
null
,
value:
'two'
));
// The dropdown icon and the selected menu item are vertically aligned.
expect
(
tester
.
getCenter
(
find
.
text
(
'two'
)).
dy
,
tester
.
getCenter
(
find
.
byType
(
Icon
)).
dy
);
// If [value] is null, the button is enabled, hint is displayed.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
onChanged
,
value:
null
,
hint:
const
Text
(
'hint'
),
disabledHint:
const
Text
(
'disabledHint'
),
));
expect
(
tester
.
getCenter
(
find
.
text
(
'hint'
)).
dy
,
tester
.
getCenter
(
find
.
byType
(
Icon
)).
dy
);
// If [value] is null, the button is disabled, [disabledHint] is displayed when [disabledHint] is non-null.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
null
,
value:
null
,
hint:
const
Text
(
'hint'
),
disabledHint:
const
Text
(
'disabledHint'
),
));
expect
(
tester
.
getCenter
(
find
.
text
(
'disabledHint'
)).
dy
,
tester
.
getCenter
(
find
.
byType
(
Icon
)).
dy
);
// If [value] is null, the button is disabled, [hint] is displayed when [disabledHint] is null.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
null
,
value:
null
,
hint:
const
Text
(
'hint'
),
disabledHint:
null
,
));
expect
(
tester
.
getCenter
(
find
.
text
(
'hint'
)).
dy
,
tester
.
getCenter
(
find
.
byType
(
Icon
)).
dy
);
int
?
getIndex
()
{
final
IndexedStack
stack
=
tester
.
element
(
find
.
byType
(
IndexedStack
)).
widget
as
IndexedStack
;
return
stack
.
index
;
}
// If [value], [hint] and [disabledHint] are null, the button is disabled, nothing displayed.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
null
,
value:
null
,
hint:
null
,
disabledHint:
null
,
));
expect
(
getIndex
(),
null
);
// If [value], [hint] and [disabledHint] are null, the button is enabled, nothing displayed.
await
tester
.
pumpWidget
(
build
(
items:
menuItems
,
onChanged:
onChanged
,
value:
null
,
hint:
null
,
disabledHint:
null
,
));
expect
(
getIndex
(),
null
);
});
testWidgets
(
'DropdowwnButton hint displays when the items list is empty, '
'items is null, and disabledHint is null'
,
...
...
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