// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; // Flutter code sample for [DropdownMenu]s. The first dropdown menu // has the default outlined border and demos using the // [DropdownMenuEntry] style parameter to customize its appearance. // The second dropdown menu customizes the appearance of the dropdown // menu's text field with its [InputDecorationTheme] parameter. void main() { runApp(const DropdownMenuExample()); } typedef ColorEntry = DropdownMenuEntry; // DropdownMenuEntry labels and values for the first dropdown menu. 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; static final List entries = UnmodifiableListView( values.map( (ColorLabel color) => ColorEntry( value: color, label: color.label, enabled: color.label != 'Grey', style: MenuItemButton.styleFrom( foregroundColor: color.color, ), ), ), ); } typedef IconEntry = DropdownMenuEntry; // DropdownMenuEntry labels and values for the second dropdown menu. enum IconLabel { smile('Smile', Icons.sentiment_satisfied_outlined), cloud('Cloud', Icons.cloud_outlined), brush('Brush', Icons.brush_outlined), heart('Heart', Icons.favorite); const IconLabel(this.label, this.icon); final String label; final IconData icon; static final List entries = UnmodifiableListView( values.map( (IconLabel icon) => IconEntry( value: icon, label: icon.label, leadingIcon: Icon(icon.icon), ), ), ); } class DropdownMenuExample extends StatefulWidget { const DropdownMenuExample({super.key}); @override State createState() => _DropdownMenuExampleState(); } class _DropdownMenuExampleState extends State { final TextEditingController colorController = TextEditingController(); final TextEditingController iconController = TextEditingController(); ColorLabel? selectedColor; IconLabel? selectedIcon; @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.green, ), home: Scaffold( body: SafeArea( child: Column( children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ DropdownMenu( initialSelection: ColorLabel.green, controller: colorController, // requestFocusOnTap is enabled/disabled by platforms when it is null. // On mobile platforms, this is false by default. Setting this to true will // trigger focus request on the text field and virtual keyboard will appear // afterward. On desktop platforms however, this defaults to true. requestFocusOnTap: true, label: const Text('Color'), onSelected: (ColorLabel? color) { setState(() { selectedColor = color; }); }, dropdownMenuEntries: ColorLabel.entries, ), const SizedBox(width: 24), DropdownMenu( controller: iconController, enableFilter: true, requestFocusOnTap: true, leadingIcon: const Icon(Icons.search), label: const Text('Icon'), inputDecorationTheme: const InputDecorationTheme( filled: true, contentPadding: EdgeInsets.symmetric(vertical: 5.0), ), onSelected: (IconLabel? icon) { setState(() { selectedIcon = icon; }); }, dropdownMenuEntries: IconLabel.entries, ), ], ), ), if (selectedColor != null && selectedIcon != null) Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('You selected a ${selectedColor?.label} ${selectedIcon?.label}'), Padding( padding: const EdgeInsets.symmetric(horizontal: 5), child: Icon( selectedIcon?.icon, color: selectedColor?.color, ), ) ], ) else const Text('Please select a color and an icon.') ], ), ), ), ); } }