Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// #region body
import 'package:material_ui/material_ui.dart';

/// Flutter code sample for [DropdownMenu] showing how to programmatically
/// clear or reset the selection using a [TextEditingController].

void main() => runApp(const DropdownMenuClearExampleApp());

class DropdownMenuClearExampleApp extends StatelessWidget {
const DropdownMenuClearExampleApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Clear DropdownMenu Sample')),
body: const Center(child: DropdownMenuClearExample()),
),
);
}
}

class DropdownMenuClearExample extends StatefulWidget {
const DropdownMenuClearExample({super.key});

@override
State<DropdownMenuClearExample> createState() =>
_DropdownMenuClearExampleState();
}

enum ColorItem {
red('Red'),
green('Green'),
blue('Blue');

const ColorItem(this.label);
final String label;
}

class _DropdownMenuClearExampleState extends State<DropdownMenuClearExample> {
final TextEditingController _controller = TextEditingController();
ColorItem? _selectedColor;

@override
void dispose() {
_controller.dispose();
super.dispose();
}

void _clearSelection() {
setState(() {
_selectedColor = null;
_controller.clear();
});
}

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownMenu<ColorItem>(
controller: _controller,
initialSelection: _selectedColor,
label: const Text('Color'),
onSelected: (ColorItem? color) {
setState(() {
_selectedColor = color;
});
},
dropdownMenuEntries: ColorItem.values
.map<DropdownMenuEntry<ColorItem>>((ColorItem color) {
return DropdownMenuEntry<ColorItem>(
value: color,
label: color.label,
);
})
.toList(),
),
const SizedBox(height: 20),
FilledButton(
onPressed: _clearSelection,
child: const Text('Clear selection'),
),
const SizedBox(height: 20),
Text('Selected: ${_selectedColor?.label ?? 'None'}'),
],
);
}
}
// #endregion body
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';
import 'package:material_ui_examples/dropdown_menu/dropdown_menu.3.dart'
as example;

void main() {
testWidgets('Selecting an entry updates the text field and state', (
WidgetTester tester,
) async {
await tester.pumpWidget(const example.DropdownMenuClearExampleApp());

expect(find.text('Selected: None'), findsOneWidget);
expect(find.widgetWithText(TextField, ''), findsOneWidget);

// Open menu and select Green.
await tester.tap(find.byType(DropdownMenu<example.ColorItem>));
await tester.pumpAndSettle();

await tester.tap(find.widgetWithText(MenuItemButton, 'Green').last);
await tester.pumpAndSettle();

expect(find.text('Selected: Green'), findsOneWidget);
expect(find.widgetWithText(TextField, 'Green'), findsOneWidget);
});

testWidgets(
'Pressing clear selection button resets the text field and state',
(WidgetTester tester) async {
await tester.pumpWidget(const example.DropdownMenuClearExampleApp());

// Open menu and select Blue.
await tester.tap(find.byType(DropdownMenu<example.ColorItem>));
await tester.pumpAndSettle();

await tester.tap(find.widgetWithText(MenuItemButton, 'Blue').last);
await tester.pumpAndSettle();

expect(find.text('Selected: Blue'), findsOneWidget);
expect(find.widgetWithText(TextField, 'Blue'), findsOneWidget);

// Tap clear button.
await tester.tap(find.widgetWithText(FilledButton, 'Clear selection'));
await tester.pumpAndSettle();

expect(find.text('Selected: None'), findsOneWidget);
expect(find.widgetWithText(TextField, ''), findsOneWidget);
},
);
}
62 changes: 59 additions & 3 deletions packages/material_ui/lib/src/dropdown_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ enum DropdownMenuCloseBehavior {
///
/// </callout-box>
///
/// <callout-box>
///
/// This sample demonstrates how to programmatically clear or reset the selection
/// in a [DropdownMenu] using a [TextEditingController].
///
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body}
///
/// </callout-box>
///
/// See also:
///
/// * [MenuAnchor], which is a widget used to mark the "anchor" for a set of submenus.
Expand Down Expand Up @@ -448,6 +461,33 @@ class DropdownMenu<T> extends StatefulWidget {
/// Controls the text being edited or selected in the menu.
///
/// If null, this widget will create its own [TextEditingController].
///
/// A [TextEditingController] can be provided to programmatically clear or modify
/// the displayed selection. For example, calling [TextEditingController.clear]
/// clears the text displayed in the dropdown menu.
///
/// When tracking the selected value in a state variable, calling
/// [TextEditingController.clear] alongside updating the state variable to null
/// is required to clear the displayed selection, as updating [initialSelection]
/// does not clear the text field.
///
/// <callout-box>
///
/// This sample demonstrates how to programmatically clear the selection in a
/// [DropdownMenu] using a [TextEditingController].
///
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body}
///
/// </callout-box>
///
/// See also:
///
/// * [initialSelection], which sets the initial selection when the widget is
/// first created.
final TextEditingController? controller;

/// The value used for an initial selection.
Expand All @@ -456,13 +496,29 @@ class DropdownMenu<T> extends StatefulWidget {
/// is first created. If the value matches one of the [dropdownMenuEntries],
/// the corresponding label will be displayed in the text field.
///
/// Setting this to null does not clear the text field.
/// Setting this to null does not clear the text field because [initialSelection]
/// only specifies an initial selection and does not act as a reactive, controlled
/// selection property.
///
/// To programmatically clear the text field, use a [TextEditingController]
/// and call [TextEditingController.clear] on it.
/// To programmatically clear or reset the selection, provide a [controller]
/// and call [TextEditingController.clear] on it alongside resetting the state
/// variable to null.
///
/// Defaults to null.
///
/// <callout-box>
///
/// This sample demonstrates how to programmatically clear the selection in a
/// [DropdownMenu] using a [TextEditingController].
///
// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/dropdown_menu/dropdown_menu.3.dart#body}
///
/// </callout-box>
///
/// See also:
///
/// * [controller], which is required to programmatically clear or modify
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
changelog: |
- Clarifies how to programmatically clear or reset the selection in `DropdownMenu`.
version: patch
Loading