-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Implement RawMenuAnchor #158255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Implement RawMenuAnchor #158255
Changes from 87 commits
Commits
Show all changes
100 commits
Select commit
Hold shift + click to select a range
d1cd1e7
Initial commit
davidhicks980 05ff4bb
Renamed parameters
davidhicks980 e2a2ac2
Changed overlay positioning to root overlay
davidhicks980 968ca1b
Added tests from MenuAnchor, fixed documentation, and made anchor pos…
davidhicks980 9c58361
Add examples and tests
davidhicks980 c1e1882
Added documentation to examples.
davidhicks980 771225b
Commented out overlay semantics test
davidhicks980 ffe8119
Implement new MenuAnchor
davidhicks980 29ced3b
Apply suggestions from code review
davidhicks980 fec1a4c
Fixed missing newline at eof
davidhicks980 f07cb67
Whitespace and documentation fixes
davidhicks980 9b783ca
Skipped test and whitespace fixes
davidhicks980 e97d529
Whitespace fixes
davidhicks980 6ac3238
Fixed traversal shortcuts not bound to actions test
davidhicks980 df518fd
Apply suggestions from code review
davidhicks980 d04c420
Added reduced test set annotation
davidhicks980 fa11f8b
Fixed imports on RawMenuAnchor
davidhicks980 e557c60
Update packages/flutter/lib/src/widgets/raw_menu_anchor.dart
davidhicks980 ec0ecaf
Add empty line to SimpleMenuApp
davidhicks980 7c22c2b
platformBrightness -> platformBrightnessOf
davidhicks980 bb36c4f
Fix broken hover test
davidhicks980 4c291ef
change MenuItemButton closeChildren to close
davidhicks980 08586bb
Pass root overlay overlayBuilder
davidhicks980 be45d28
Accidentally switched around the layerlink
davidhicks980 9e511b4
Fixed layerlink!
davidhicks980 ecc6015
TapRegionGroupId wasn't passed to menu anchor tap region
davidhicks980 65a3b94
Changed offsetted to offset, since offsetted is rarely used (though t…
davidhicks980 a84c9ab
Fixed leaky and platform-dependent tests
davidhicks980 e6c8557
Removed redundant kIsWeb check
davidhicks980 569bc69
Move MediaQuery into a builder
davidhicks980 3ee30c2
Fix mediaquery
davidhicks980 d9e6904
Replaced _RawMenuAnchor._maybeOf with MenuController.maybeOf _anchor
davidhicks980 347f641
Fixed _internalMenuController initial assignment
davidhicks980 360744c
Apply whitespace fixes and remove golden.
davidhicks980 76bf3e9
Forgot one golden
davidhicks980 7c4d2cf
Very cosmetic changes in test comments
bleroux c3fdc65
Merge branch 'flutter:master' into raw_menu_anchor
davidhicks980 cd74b91
Fix anchorRect respects ancestor transformations
davidhicks980 1b4d05e
Apply suggestions from code review
davidhicks980 6816dcb
Merge branch 'master' into raw_menu_anchor
davidhicks980 3d9c2a1
Added useRootOverlay property and refined nomenclature.
davidhicks980 f0ee3c1
Remove duplicate OverlayPortal branch.
davidhicks980 4dbe849
Fix overlay branch removal
davidhicks980 59ddbe3
Merge remote-tracking branch 'origin/master' into raw_menu_anchor
davidhicks980 9a94a49
Format raw_menu_anchor_test
davidhicks980 314e9a9
Fix menu anchor test
davidhicks980 8d1deb1
Remove unnecessary null coalescing statement.
davidhicks980 0513904
Replace menuChildren with child, pass Widget to builders.
davidhicks980 db371b1
Fix testing errors and add assertions
davidhicks980 3486ed4
Fixed CI formatting.
davidhicks980 302d415
Merge branch 'master' into raw_menu_anchor
davidhicks980 dc5192c
Merge branch 'master' into raw_menu_anchor
davidhicks980 187a241
Fix snippet error
davidhicks980 9f89939
Move _RawMenuAnchor properties into constructor
davidhicks980 25483fc
Refactor _findClosestScreen for performance
davidhicks980 6aaf82e
Apply Nate's changes
davidhicks980 a7f026d
Add createDependency tests
davidhicks980 0ce1226
Add hover traversal tests for menubar example
davidhicks980 2c2a441
Run format
davidhicks980 953ae7b
Merge branch 'master' into raw_menu_anchor
davidhicks980 67f7665
Merge branch 'master' into raw_menu_anchor
davidhicks980 e469999
Add fixes from Tong review.
davidhicks980 2a84aea
Make private params required
davidhicks980 59915d8
Fix errors in example,
davidhicks980 192a8c1
Remove redundant padding
davidhicks980 4e475d4
Merge branch 'master' into raw_menu_anchor
davidhicks980 112c23f
Remove _RawMenuAnchorOverlay intermediary.
davidhicks980 5fa25ba
Merge branch 'master' into raw_menu_anchor
davidhicks980 cb8b972
Fixed broken examples
davidhicks980 83e15a5
Merge branch 'master' into raw_menu_anchor
davidhicks980 f635576
Merge branch 'master' into raw_menu_anchor
davidhicks980 e11b1f1
Rename withOverlayBuilder to fromOverlayBuilder
davidhicks980 4fe9843
Tong suggestions and example 2 test fix.
davidhicks980 158e92a
Fix example animation test
davidhicks980 fef8e05
Fix formatting
davidhicks980 b6d3da6
Indent 2_test
davidhicks980 8d183aa
Documentation fixes.
davidhicks980 13c1323
Remove default constructor
davidhicks980 e9e19bc
Fix Bruno comments
davidhicks980 2d01fea
Fix undefined snippet variable
davidhicks980 2d878a9
Fix shown imports
davidhicks980 8bca9cb
Convert _RawMenuAnchorState to _RawMenuAnchorBaseMixin
davidhicks980 c50c719
Merge branch 'main' of github.com:flutter/flutter into raw_menu_anchor
davidhicks980 4483696
Format menu anchor
davidhicks980 9c46904
Fix old docs
davidhicks980 4be73d8
Add additional documentation to _RawMenuAnchorBaseMixin
davidhicks980 1b27b55
Fix scopes route errors.
davidhicks980 6b3f351
Fix menu anchor style formatting
davidhicks980 6429823
Add maybeIsOpenOf and removed createDependency on maybeOf
davidhicks980 ace0e3e
Made MenuController required.
davidhicks980 b3d0979
Use getInheritedWidgetOfExactType for _MenuAnchorScope and detach Men…
davidhicks980 f3e24d2
Fix test errors.
davidhicks980 94ee602
Remove position reference.
davidhicks980 22695f1
Merge branch 'master' into raw_menu_anchor
davidhicks980 55cd12d
Fix semantics node
davidhicks980 4cd4009
Merge branch 'master' into raw_menu_anchor
davidhicks980 1daeeb8
Fix MenuController documentation.
davidhicks980 ea46e13
Fix MenuController documentation
davidhicks980 206e5e5
Merge branch 'master' into raw_menu_anchor
chunhtai e1f30ae
Merge branch 'master' into raw_menu_anchor
chunhtai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
184 changes: 184 additions & 0 deletions
184
examples/api/lib/widgets/raw_menu_anchor/raw_menu_anchor.0.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| // 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/semantics.dart'; | ||
| import 'package:flutter/services.dart'; | ||
|
|
||
| /// Flutter code sample for a [RawMenuAnchor] that demonstrates | ||
| /// how to create a simple menu. | ||
| void main() { | ||
| runApp(const RawMenuAnchorApp()); | ||
| } | ||
|
|
||
| enum Animal { | ||
| cat('Cat', leading: Text('🦁')), | ||
| kitten('Kitten', leading: Text('🐱')), | ||
| felisCatus('Felis catus', leading: Text('🐈')), | ||
| dog('Dog', leading: Text('🐕')); | ||
|
|
||
| const Animal(this.label, {this.leading}); | ||
| final String label; | ||
| final Widget? leading; | ||
| } | ||
|
|
||
| class RawMenuAnchorExample extends StatefulWidget { | ||
| const RawMenuAnchorExample({super.key}); | ||
|
|
||
| @override | ||
| State<RawMenuAnchorExample> createState() => _RawMenuAnchorExampleState(); | ||
| } | ||
|
|
||
| class _RawMenuAnchorExampleState extends State<RawMenuAnchorExample> { | ||
| final FocusNode focusNode = FocusNode(); | ||
| final MenuController controller = MenuController(); | ||
| Animal? _selectedAnimal; | ||
|
|
||
| @override | ||
| void dispose() { | ||
| focusNode.dispose(); | ||
| super.dispose(); | ||
| } | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| final ThemeData theme = Theme.of(context); | ||
| return UnconstrainedBox( | ||
| clipBehavior: Clip.hardEdge, | ||
| child: Row( | ||
| mainAxisSize: MainAxisSize.min, | ||
| children: <Widget>[ | ||
| Text('Favorite Animal:', style: theme.textTheme.titleMedium), | ||
| const SizedBox(width: 8), | ||
| CustomMenu( | ||
| controller: controller, | ||
| focusNode: focusNode, | ||
| anchor: FilledButton( | ||
| focusNode: focusNode, | ||
| style: FilledButton.styleFrom(fixedSize: const Size(172, 36)), | ||
| onPressed: () { | ||
| if (controller.isOpen) { | ||
| controller.close(); | ||
| } else { | ||
| controller.open(); | ||
| } | ||
| }, | ||
| child: Row( | ||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||
| children: <Widget>[ | ||
| Expanded(flex: 3, child: Text(_selectedAnimal?.label ?? 'Select One')), | ||
| const Flexible(child: Icon(Icons.arrow_drop_down, size: 16)), | ||
| ], | ||
| ), | ||
| ), | ||
| children: <Widget>[ | ||
| for (final Animal animal in Animal.values) | ||
| MenuItemButton( | ||
| autofocus: _selectedAnimal == animal, | ||
| onPressed: () { | ||
| setState(() { | ||
| _selectedAnimal = animal; | ||
| }); | ||
| controller.close(); | ||
| }, | ||
| leadingIcon: SizedBox(width: 24, child: Center(child: animal.leading)), | ||
| trailingIcon: | ||
| _selectedAnimal == animal ? const Icon(Icons.check, size: 20) : null, | ||
| child: Text(animal.label), | ||
| ), | ||
| ], | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| class CustomMenu extends StatelessWidget { | ||
| const CustomMenu({ | ||
| super.key, | ||
| required this.children, | ||
| required this.anchor, | ||
| required this.controller, | ||
| required this.focusNode, | ||
| }); | ||
|
|
||
| final List<Widget> children; | ||
| final Widget anchor; | ||
| final MenuController controller; | ||
| final FocusNode focusNode; | ||
|
|
||
| static const Map<ShortcutActivator, Intent> _shortcuts = <ShortcutActivator, Intent>{ | ||
| SingleActivator(LogicalKeyboardKey.gameButtonA): ActivateIntent(), | ||
| SingleActivator(LogicalKeyboardKey.escape): DismissIntent(), | ||
| SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), | ||
| SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), | ||
| }; | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return RawMenuAnchor( | ||
| controller: controller, | ||
| childFocusNode: focusNode, | ||
| overlayBuilder: (BuildContext context, RawMenuOverlayInfo info) { | ||
| return Positioned( | ||
| top: info.anchorRect.bottom + 4, | ||
| left: info.anchorRect.left, | ||
| // The overlay will be treated as a dialog. SemanticsProperties.label can | ||
| // be set to a localized string to describe the dialog. | ||
| child: Semantics.fromProperties( | ||
| explicitChildNodes: true, | ||
| properties: const SemanticsProperties(scopesRoute: true), | ||
| child: TapRegion( | ||
| groupId: info.tapRegionGroupId, | ||
| onTapOutside: (PointerDownEvent event) { | ||
| MenuController.maybeOf(context)?.close(); | ||
| }, | ||
| child: FocusScope( | ||
| child: IntrinsicWidth( | ||
| child: Container( | ||
| clipBehavior: Clip.antiAlias, | ||
| constraints: const BoxConstraints(minWidth: 168), | ||
| padding: const EdgeInsets.symmetric(vertical: 6), | ||
| decoration: BoxDecoration( | ||
| color: Theme.of(context).colorScheme.surface, | ||
| borderRadius: BorderRadius.circular(6), | ||
| boxShadow: kElevationToShadow[4], | ||
| ), | ||
| child: Shortcuts(shortcuts: _shortcuts, child: Column(children: children)), | ||
| ), | ||
| ), | ||
| ), | ||
| ), | ||
| ), | ||
| ); | ||
| }, | ||
| child: anchor, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| class RawMenuAnchorApp extends StatelessWidget { | ||
| const RawMenuAnchorApp({super.key}); | ||
|
|
||
| static const ButtonStyle menuButtonStyle = ButtonStyle( | ||
| overlayColor: WidgetStatePropertyAll<Color>(Color.fromARGB(55, 139, 195, 255)), | ||
| iconSize: WidgetStatePropertyAll<double>(17), | ||
| padding: WidgetStatePropertyAll<EdgeInsets>(EdgeInsets.symmetric(horizontal: 12)), | ||
| ); | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return MaterialApp( | ||
| theme: ThemeData.from( | ||
| useMaterial3: true, | ||
| colorScheme: ColorScheme.fromSeed( | ||
| seedColor: Colors.blue, | ||
| dynamicSchemeVariant: DynamicSchemeVariant.vibrant, | ||
| ), | ||
| ).copyWith(menuButtonTheme: const MenuButtonThemeData(style: menuButtonStyle)), | ||
| home: const Scaffold(body: Center(child: RawMenuAnchorExample())), | ||
| ); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.