Skip to content

Commit 17ad052

Browse files
authored
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](flutter/flutter#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
1 parent 919bed6 commit 17ad052

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

packages/flutter/lib/src/material/dropdown_menu.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
830830
focusNode: widget.focusNode,
831831
canRequestFocus: canRequestFocus(),
832832
enableInteractiveSelection: canRequestFocus(),
833+
readOnly: !canRequestFocus(),
833834
keyboardType: widget.keyboardType,
834835
textAlign: widget.textAlign,
835836
textAlignVertical: TextAlignVertical.center,

packages/flutter/test/material/dropdown_menu_test.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,6 +2442,7 @@ void main() {
24422442
MaterialApp(
24432443
home: Scaffold(
24442444
body: DropdownMenu<String>(
2445+
requestFocusOnTap: true,
24452446
controller: controller,
24462447
dropdownMenuEntries: const <DropdownMenuEntry<String>>[
24472448
DropdownMenuEntry<String>(
@@ -2675,6 +2676,53 @@ void main() {
26752676
expect(find.widgetWithText(MenuItemButton, menu.label), findsNWidgets(2));
26762677
}
26772678
});
2679+
2680+
// This is a regression test for https://github.com/flutter/flutter/issues/151686.
2681+
testWidgets('Setting DropdownMenu.requestFocusOnTap to false makes TextField read only', (WidgetTester tester) async {
2682+
const String label = 'Test';
2683+
Widget buildDropdownMenu({ bool? requestFocusOnTap }) {
2684+
return MaterialApp(
2685+
home: Scaffold(
2686+
body: Center(
2687+
child: DropdownMenu<TestMenu>(
2688+
requestFocusOnTap: requestFocusOnTap,
2689+
dropdownMenuEntries: menuChildren,
2690+
hintText: label,
2691+
),
2692+
),
2693+
),
2694+
);
2695+
}
2696+
await tester.pumpWidget(buildDropdownMenu(requestFocusOnTap: true));
2697+
2698+
expect(
2699+
tester.getSemantics(find.byType(TextField)),
2700+
matchesSemantics(
2701+
hasFocusAction: true,
2702+
hasTapAction: true,
2703+
isTextField: true,
2704+
hasEnabledState: true,
2705+
isEnabled: true,
2706+
label: 'Test',
2707+
textDirection: TextDirection.ltr,
2708+
),
2709+
);
2710+
2711+
await tester.pumpWidget(buildDropdownMenu(requestFocusOnTap: false));
2712+
2713+
expect(
2714+
tester.getSemantics(find.byType(TextField)),
2715+
matchesSemantics(
2716+
hasFocusAction: true,
2717+
isTextField: true,
2718+
hasEnabledState: true,
2719+
isEnabled: true,
2720+
label: 'Test',
2721+
isReadOnly: true,
2722+
textDirection: TextDirection.ltr,
2723+
),
2724+
);
2725+
});
26782726
}
26792727

26802728
enum TestMenu {

0 commit comments

Comments
 (0)