diff --git a/examples/api/lib/material/menu_anchor/menu_anchor.3.dart b/examples/api/lib/material/menu_anchor/menu_anchor.3.dart new file mode 100644 index 0000000000000..2995fb9ec12f2 --- /dev/null +++ b/examples/api/lib/material/menu_anchor/menu_anchor.3.dart @@ -0,0 +1,81 @@ +// 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 [SimpleCascadingMenuApp]. + +void main() => runApp(const SimpleCascadingMenuApp()); + +/// A Simple Cascading Menu example using the [MenuAnchor] Widget. +class MyCascadingMenu extends StatefulWidget { + const MyCascadingMenu({super.key}); + + @override + State createState() => _MyCascadingMenuState(); +} + +class _MyCascadingMenuState extends State { + final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button'); + + @override + void dispose() { + _buttonFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MenuAnchor( + childFocusNode: _buttonFocusNode, + menuChildren: [ + MenuItemButton( + onPressed: () {}, + child: const Text('Revert'), + ), + MenuItemButton( + onPressed: () {}, + child: const Text('Setting'), + ), + MenuItemButton( + onPressed: () {}, + child: const Text('Send Feedback'), + ), + ], + builder: (_, MenuController controller, Widget? child) { + return IconButton( + focusNode: _buttonFocusNode, + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + icon: const Icon(Icons.more_vert), + ); + }, + ); + } +} + +/// Top Level Application Widget. +class SimpleCascadingMenuApp extends StatelessWidget { + const SimpleCascadingMenuApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + home: Scaffold( + appBar: AppBar( + title: const Text('MenuAnchor Simple Example'), + actions: const [ + MyCascadingMenu(), + ], + ), + ), + ); + } +} diff --git a/examples/api/test/material/menu_anchor/menu_anchor.3_test.dart b/examples/api/test/material/menu_anchor/menu_anchor.3_test.dart new file mode 100644 index 0000000000000..ee9172c84b8c0 --- /dev/null +++ b/examples/api/test/material/menu_anchor/menu_anchor.3_test.dart @@ -0,0 +1,36 @@ +// 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'; +import 'package:flutter_api_samples/material/menu_anchor/menu_anchor.3.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Menu button opens and closes the menu', (WidgetTester tester) async { + await tester.pumpWidget(const example.SimpleCascadingMenuApp()); + + // Find the menu button. + final Finder menuButton = find.byType(IconButton); + expect(menuButton, findsOneWidget); + + // Tap the menu button to open the menu. + await tester.tap(menuButton); + await tester.pumpAndSettle(); + + // Verify that the menu is open. + expect(find.text('Revert'), findsOneWidget); + + // Tap the menu button again to close the menu. + await tester.tap(menuButton); + await tester.pumpAndSettle(); + + // Verify that the menu is closed. + expect(find.text('Revert'), findsNothing); + }); + + testWidgets('Does not show debug banner', (WidgetTester tester) async { + await tester.pumpWidget(const example.SimpleCascadingMenuApp()); + expect(find.byType(CheckedModeBanner), findsNothing); + }); +} diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index b01395a8eed39..04b7865106d71 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -119,6 +119,13 @@ typedef MenuAnchorChildBuilder = Widget Function( /// /// ** See code in examples/api/lib/material/menu_anchor/menu_anchor.1.dart ** /// {@end-tool} +/// +/// {@tool dartpad} +/// This example demonstrates a simplified cascading menu using the [MenuAnchor] +/// widget. +/// +/// ** See code in examples/api/lib/material/menu_anchor/menu_anchor.3.dart ** +/// {@end-tool} class MenuAnchor extends StatefulWidget { /// Creates a const [MenuAnchor]. ///