Unverified Commit 6848110f authored by Leigha Jarett's avatar Leigha Jarett Committed by GitHub

Update menu API docs to help developers migrate to m3 (#128351)

Fixes: https://github.com/flutter/flutter/issues/127215
parent 96afa500
// 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:flutter/material.dart';
/// Flutter code sample for [DropdownMenu].
const List<String> list = <String>['One', 'Two', 'Three', 'Four'];
void main() => runApp(const DropdownMenuApp());
class DropdownMenuApp extends StatelessWidget {
const DropdownMenuApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3:true),
home: Scaffold(
appBar: AppBar(title: const Text('DropdownMenu Sample')),
body: const Center(
child: DropdownMenuExample(),
),
),
);
}
}
class DropdownMenuExample extends StatefulWidget {
const DropdownMenuExample({super.key});
@override
State<DropdownMenuExample> createState() => _DropdownMenuExampleState();
}
class _DropdownMenuExampleState extends State<DropdownMenuExample> {
String dropdownValue = list.first;
@override
Widget build(BuildContext context) {
return DropdownMenu<String>(
initialSelection: list.first,
onSelected: (String? value) {
// This is called when the user selects an item.
setState(() {
dropdownValue = value!;
});
},
dropdownMenuEntries: list.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(
value: value,
label: value
);
}).toList(),
);
}
}
// 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:flutter/material.dart';
/// Flutter code sample for [MenuAnchor].
// This is the type used by the menu below.
enum SampleItem { itemOne, itemTwo, itemThree }
void main() => runApp(const MenuAnchorApp());
class MenuAnchorApp extends StatelessWidget {
const MenuAnchorApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const MenuAnchorExample(),
);
}
}
class MenuAnchorExample extends StatefulWidget {
const MenuAnchorExample({super.key});
@override
State<MenuAnchorExample> createState() => _MenuAnchorExampleState();
}
class _MenuAnchorExampleState extends State<MenuAnchorExample> {
SampleItem? selectedMenu;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MenuAnchorButton')),
body: Center(
child: MenuAnchor(
builder:
(BuildContext context, MenuController controller, Widget? child) {
return IconButton(
onPressed: () {
if (controller.isOpen) {
controller.close();
} else {
controller.open();
}
},
icon: const Icon(Icons.more_horiz),
tooltip: 'Show menu',
);},
menuChildren: List<MenuItemButton>.generate(
3,
(int index) => MenuItemButton(
onPressed: () => setState(() => selectedMenu = SampleItem.values[index]),
child: Text('Item ${index + 1}'),
),
),
),
),
);
}
}
...@@ -788,6 +788,44 @@ class DropdownButtonHideUnderline extends InheritedWidget { ...@@ -788,6 +788,44 @@ class DropdownButtonHideUnderline extends InheritedWidget {
/// shows the currently selected item as well as an arrow that opens a menu for /// shows the currently selected item as well as an arrow that opens a menu for
/// selecting another item. /// selecting another item.
/// ///
/// ## Updating to [DropdownMenu]
///
/// There is a Material 3 version of this component,
/// [DropdownMenu] that is preferred for applications that are configured
/// for Material 3 (see [ThemeData.useMaterial3]).
/// The [DropdownMenu] widget's visuals
/// are a little bit different, see the Material 3 spec at
/// <https://m3.material.io/components/menus/guidelines> for
/// more details.
///
/// The [DropdownMenu] widget's API is also slightly different.
/// To update from [DropdownButton] to [DropdownMenu], you will
/// need to make the following changes:
///
/// 1. Instead of using [DropdownButton.items], which
/// takes a list of [DropdownMenuItem]s, use
/// [DropdownMenu.dropdownMenuEntries], which
/// takes a list of [DropdownMenuEntry]'s.
///
/// 2. Instead of using [DropdownButton.onChanged],
/// use [DropdownMenu.onSelected], which is also
/// a callback that is called when the user selects an entry.
///
/// 3. In [DropdownMenu] it is not required to track
/// the current selection in your app's state.
/// So, instead of tracking the current selection in
/// the [DropdownButton.value] property, you can set the
/// [DropdownMenu.initialSelection] property to the
/// item that should be selected before there is any user action.
///
/// 4. You may also need to make changes to the styling of the
/// [DropdownMenu], see the properties in the [DropdownMenu]
/// constructor for more details.
///
/// See the sample below for an example of migrating
/// from [DropdownButton] to [DropdownMenu].
///
/// ## Using [DropdownButton]
/// {@youtube 560 315 https://www.youtube.com/watch?v=ZzQ_PWrFihg} /// {@youtube 560 315 https://www.youtube.com/watch?v=ZzQ_PWrFihg}
/// ///
/// One ancestor must be a [Material] widget and typically this is /// One ancestor must be a [Material] widget and typically this is
...@@ -802,6 +840,7 @@ class DropdownButtonHideUnderline extends InheritedWidget { ...@@ -802,6 +840,7 @@ class DropdownButtonHideUnderline extends InheritedWidget {
/// dropdown's value. It should also call [State.setState] to rebuild the /// dropdown's value. It should also call [State.setState] to rebuild the
/// dropdown with the new value. /// dropdown with the new value.
/// ///
///
/// {@tool dartpad} /// {@tool dartpad}
/// This sample shows a [DropdownButton] with a large arrow icon, /// This sample shows a [DropdownButton] with a large arrow icon,
/// purple text style, and bold purple underline, whose value is one of "One", /// purple text style, and bold purple underline, whose value is one of "One",
...@@ -819,9 +858,13 @@ class DropdownButtonHideUnderline extends InheritedWidget { ...@@ -819,9 +858,13 @@ class DropdownButtonHideUnderline extends InheritedWidget {
/// [disabledHint] is null and [hint] is non-null, the [hint] widget will /// [disabledHint] is null and [hint] is non-null, the [hint] widget will
/// instead be displayed. /// instead be displayed.
/// ///
/// Requires one of its ancestors to be a [Material] widget. /// {@tool dartpad}
/// This sample shows how you would rewrite the above [DropdownButton]
/// to use the [DropdownMenu].
///
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.1.dart **
/// {@end-tool}
/// ///
/// {@youtube 560 315 https://www.youtube.com/watch?v=ZzQ_PWrFihg}
/// ///
/// See also: /// See also:
/// ///
......
...@@ -1014,6 +1014,41 @@ typedef PopupMenuItemBuilder<T> = List<PopupMenuEntry<T>> Function(BuildContext ...@@ -1014,6 +1014,41 @@ typedef PopupMenuItemBuilder<T> = List<PopupMenuEntry<T>> Function(BuildContext
/// If both are null, then a standard overflow icon is created (depending on the /// If both are null, then a standard overflow icon is created (depending on the
/// platform). /// platform).
/// ///
/// /// ## Updating to [MenuAnchor]
///
/// There is a Material 3 component,
/// [MenuAnchor] that is preferred for applications that are configured
/// for Material 3 (see [ThemeData.useMaterial3]).
/// The [MenuAnchor] widget's visuals
/// are a little bit different, see the Material 3 spec at
/// <https://m3.material.io/components/menus/guidelines> for
/// more details.
///
/// The [MenuAnchor] widget's API is also slightly different.
/// [MenuAnchor]'s were built to be lower level interface for
/// creating menus that are displayed from an anchor.
///
/// There are a few steps you would take to migrate from
/// [PopupMenuButton] to [MenuAnchor]:
///
/// 1. Instead of using the [PopupMenuButton.itemBuilder] to build
/// a list of [PopupMenuEntry]s, you would use the [MenuAnchor.menuChildren]
/// which takes a list of [Widget]s. Usually, you would use a list of
/// [MenuItemButton]s as shown in the example below.
///
/// 2. Instead of using the [PopupMenuButton.onSelected] callback, you would
/// set individual callbacks for each of the [MenuItemButton]s using the
/// [MenuItemButton.onPressed] property.
///
/// 3. To anchor the [MenuAnchor] to a widget, you would use the [MenuAnchor.builder]
/// to return the widget of choice - usually a [TextButton] or an [IconButton].
///
/// 4. You may want to style the [MenuItemButton]s, see the [MenuItemButton]
/// documentation for details.
///
/// Use the sample below for an example of migrating from [PopupMenuButton] to
/// [MenuAnchor].
///
/// {@tool dartpad} /// {@tool dartpad}
/// This example shows a menu with three items, selecting between an enum's /// This example shows a menu with three items, selecting between an enum's
/// values and setting a `selectedMenu` field based on the selection. /// values and setting a `selectedMenu` field based on the selection.
...@@ -1022,6 +1057,12 @@ typedef PopupMenuItemBuilder<T> = List<PopupMenuEntry<T>> Function(BuildContext ...@@ -1022,6 +1057,12 @@ typedef PopupMenuItemBuilder<T> = List<PopupMenuEntry<T>> Function(BuildContext
/// {@end-tool} /// {@end-tool}
/// ///
/// {@tool dartpad} /// {@tool dartpad}
/// This example shows how to migrate the above to a [MenuAnchor].
///
/// ** See code in examples/api/lib/material/menu_anchor/menu_anchor.2.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// This sample shows the creation of a popup menu, as described in: /// This sample shows the creation of a popup menu, as described in:
/// https://m3.material.io/components/menus/overview /// https://m3.material.io/components/menus/overview
/// ///
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment