Fix DropdownMenu can be focused and updated when disabled (#149737)
## Description This PRs fixes `DropdownMenu` behaviors when disabled. Before this PR the `DropdownMenu` value can be changed when `DropdownMenu.enabled` was false because the inner `IconButton` was not disabled so it can get focus (for instance using tab key). After this PR, the inner `TextField` and the inner `IconButton` are disabled when `DropdownMenu.enabled` is false. ## Related Issue Fixes https://github.com/flutter/flutter/issues/149598. ## Tests Updates 1 test. Adds 1 test.
This commit is contained in:
parent
ad462e2783
commit
fdb74fd3e7
@ -655,7 +655,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
style: effectiveStyle,
|
style: effectiveStyle,
|
||||||
leadingIcon: entry.leadingIcon,
|
leadingIcon: entry.leadingIcon,
|
||||||
trailingIcon: entry.trailingIcon,
|
trailingIcon: entry.trailingIcon,
|
||||||
onPressed: entry.enabled
|
onPressed: entry.enabled && widget.enabled
|
||||||
? () {
|
? () {
|
||||||
_localTextEditingController?.value = TextEditingValue(
|
_localTextEditingController?.value = TextEditingValue(
|
||||||
text: entry.label,
|
text: entry.label,
|
||||||
@ -676,7 +676,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
|
|
||||||
void handleUpKeyInvoke(_) {
|
void handleUpKeyInvoke(_) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (!_menuHasEnabledItem || !_controller.isOpen) {
|
if (!widget.enabled || !_menuHasEnabledItem || !_controller.isOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_enableFilter = false;
|
_enableFilter = false;
|
||||||
@ -695,7 +695,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
|
|
||||||
void handleDownKeyInvoke(_) {
|
void handleDownKeyInvoke(_) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (!_menuHasEnabledItem || !_controller.isOpen) {
|
if (!widget.enabled || !_menuHasEnabledItem || !_controller.isOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_enableFilter = false;
|
_enableFilter = false;
|
||||||
@ -786,7 +786,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
isSelected: controller.isOpen,
|
isSelected: controller.isOpen,
|
||||||
icon: widget.trailingIcon ?? const Icon(Icons.arrow_drop_down),
|
icon: widget.trailingIcon ?? const Icon(Icons.arrow_drop_down),
|
||||||
selectedIcon: widget.selectedTrailingIcon ?? const Icon(Icons.arrow_drop_up),
|
selectedIcon: widget.selectedTrailingIcon ?? const Icon(Icons.arrow_drop_up),
|
||||||
onPressed: () {
|
onPressed: !widget.enabled ? null : () {
|
||||||
handlePressed(controller);
|
handlePressed(controller);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -799,6 +799,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
|
|
||||||
final Widget textField = TextField(
|
final Widget textField = TextField(
|
||||||
key: _anchorKey,
|
key: _anchorKey,
|
||||||
|
enabled: widget.enabled,
|
||||||
mouseCursor: effectiveMouseCursor,
|
mouseCursor: effectiveMouseCursor,
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
canRequestFocus: canRequestFocus(),
|
canRequestFocus: canRequestFocus(),
|
||||||
@ -825,7 +826,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
}
|
}
|
||||||
controller.close();
|
controller.close();
|
||||||
},
|
},
|
||||||
onTap: () {
|
onTap: !widget.enabled ? null : () {
|
||||||
handlePressed(controller);
|
handlePressed(controller);
|
||||||
},
|
},
|
||||||
onChanged: (String text) {
|
onChanged: (String text) {
|
||||||
@ -837,7 +838,6 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
|||||||
},
|
},
|
||||||
inputFormatters: widget.inputFormatters,
|
inputFormatters: widget.inputFormatters,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
enabled: widget.enabled,
|
|
||||||
label: widget.label,
|
label: widget.label,
|
||||||
hintText: widget.hintText,
|
hintText: widget.hintText,
|
||||||
helperText: widget.helperText,
|
helperText: widget.helperText,
|
||||||
|
@ -83,11 +83,9 @@ void main() {
|
|||||||
expect(material.textStyle?.height, 1.43);
|
expect(material.textStyle?.height, 1.43);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DropdownMenu can be disabled', (WidgetTester tester) async {
|
testWidgets('Inner TextField is disabled when DropdownMenu is disabled', (WidgetTester tester) async {
|
||||||
final ThemeData themeData = ThemeData();
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: themeData,
|
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: DropdownMenu<TestMenu>(
|
child: DropdownMenu<TestMenu>(
|
||||||
@ -100,7 +98,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final TextField textField = tester.widget(find.byType(TextField));
|
final TextField textField = tester.widget(find.byType(TextField));
|
||||||
expect(textField.decoration?.enabled, false);
|
expect(textField.enabled, false);
|
||||||
final Finder menuMaterial = find.ancestor(
|
final Finder menuMaterial = find.ancestor(
|
||||||
of: find.byType(SingleChildScrollView),
|
of: find.byType(SingleChildScrollView),
|
||||||
matching: find.byType(Material),
|
matching: find.byType(Material),
|
||||||
@ -116,6 +114,25 @@ void main() {
|
|||||||
expect(updatedMenuMaterial, findsNothing);
|
expect(updatedMenuMaterial, findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Inner IconButton is disabled when DropdownMenu is disabled', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/149598.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: SafeArea(
|
||||||
|
child: DropdownMenu<TestMenu>(
|
||||||
|
enabled: false,
|
||||||
|
dropdownMenuEntries: menuChildren,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final IconButton trailingButton = tester.widget(find.widgetWithIcon(IconButton, Icons.arrow_drop_down).first);
|
||||||
|
expect(trailingButton.onPressed, null);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Material2 - The width of the text field should always be the same as the menu view',
|
testWidgets('Material2 - The width of the text field should always be the same as the menu view',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user