Make TextField read only when the text input is disabled by setting DropdownMenu.requestFocusOnTap to false (#153566)
Fixes [[DropdownMenu] Semantics still reads out "EditBox" when text editing is disabled](https://github.com/flutter/flutter/issues/151686) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() { runApp(const DropdownMenuExample()); } enum ColorLabel { blue('Blue', Colors.blue), pink('Pink', Colors.pink), green('Green', Colors.green), yellow('Orange', Colors.orange), grey('Grey', Colors.grey); const ColorLabel(this.label, this.color); final String label; final Color color; } class DropdownMenuExample extends StatefulWidget { const DropdownMenuExample({super.key}); @override State<DropdownMenuExample> createState() => _DropdownMenuExampleState(); } class _DropdownMenuExampleState extends State<DropdownMenuExample> { ColorLabel? selectedColor; @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, spacing: 16.0, children: <Widget>[ const ExcludeSemantics(child: Text('TexField')), const TextField( readOnly: true, decoration: InputDecoration( labelText: 'Color', border: OutlineInputBorder(), ), ), const ExcludeSemantics(child: Text('DropdownMenu')), DropdownMenu<ColorLabel>( requestFocusOnTap: false, label: const Text('Color'), dropdownMenuEntries: ColorLabel.values .map<DropdownMenuEntry<ColorLabel>>((ColorLabel color) { return DropdownMenuEntry<ColorLabel>( value: color, label: color.label, style: MenuItemButton.styleFrom( foregroundColor: color.color, ), ); }).toList(), ), ], ), ), ), ), ); } } ``` </details> ### Preview (with Talkback captions) |Before | After | | --------------- | --------------- | | <img src="https://github.com/user-attachments/assets/0d9f79f3-de5d-4c42-adea-3d700464d001" /> | <img src="https://github.com/user-attachments/assets/cf38508e-61f7-43ff-b420-ffe24cc8e28f" /> | ### Before demo DropdownMenu announces "EditBox" and "double tap to activate" when setting `DropdownMenu.requestFocusOnTap` to `false` shouldn't allow that https://github.com/user-attachments/assets/f692a4f6-9d6a-4834-8df0-baf6c65fae29 ### After demo When setting `DropdownMenu.requestFocusOnTap` to `false`, the underlying `TextField` gets read only state which changes the semantics to be not editable or focusable and remove"EditBox" and "double tap to activate" announcments https://github.com/user-attachments/assets/0e14a636-6b81-4535-a5d1-c8f301c4f89e
This commit is contained in:
@@ -830,6 +830,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
||||
focusNode: widget.focusNode,
|
||||
canRequestFocus: canRequestFocus(),
|
||||
enableInteractiveSelection: canRequestFocus(),
|
||||
readOnly: !canRequestFocus(),
|
||||
keyboardType: widget.keyboardType,
|
||||
textAlign: widget.textAlign,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
|
||||
@@ -2442,6 +2442,7 @@ void main() {
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: DropdownMenu<String>(
|
||||
requestFocusOnTap: true,
|
||||
controller: controller,
|
||||
dropdownMenuEntries: const <DropdownMenuEntry<String>>[
|
||||
DropdownMenuEntry<String>(
|
||||
@@ -2675,6 +2676,53 @@ void main() {
|
||||
expect(find.widgetWithText(MenuItemButton, menu.label), findsNWidgets(2));
|
||||
}
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/151686.
|
||||
testWidgets('Setting DropdownMenu.requestFocusOnTap to false makes TextField read only', (WidgetTester tester) async {
|
||||
const String label = 'Test';
|
||||
Widget buildDropdownMenu({ bool? requestFocusOnTap }) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: DropdownMenu<TestMenu>(
|
||||
requestFocusOnTap: requestFocusOnTap,
|
||||
dropdownMenuEntries: menuChildren,
|
||||
hintText: label,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildDropdownMenu(requestFocusOnTap: true));
|
||||
|
||||
expect(
|
||||
tester.getSemantics(find.byType(TextField)),
|
||||
matchesSemantics(
|
||||
hasFocusAction: true,
|
||||
hasTapAction: true,
|
||||
isTextField: true,
|
||||
hasEnabledState: true,
|
||||
isEnabled: true,
|
||||
label: 'Test',
|
||||
textDirection: TextDirection.ltr,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(buildDropdownMenu(requestFocusOnTap: false));
|
||||
|
||||
expect(
|
||||
tester.getSemantics(find.byType(TextField)),
|
||||
matchesSemantics(
|
||||
hasFocusAction: true,
|
||||
isTextField: true,
|
||||
hasEnabledState: true,
|
||||
isEnabled: true,
|
||||
label: 'Test',
|
||||
isReadOnly: true,
|
||||
textDirection: TextDirection.ltr,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
enum TestMenu {
|
||||
|
||||
Reference in New Issue
Block a user