[material/menu_anchor.dart] Add animations to MenuAnchor.#176494
[material/menu_anchor.dart] Add animations to MenuAnchor.#176494davidhicks980 merged 67 commits intoflutter:masterfrom
Conversation
|
Looks good and seems consistent with https://m3.material.io/components/menus/guidelines#691d98ba-0375-4681-8c47-a5c3e7b58798. Only suggestion I would have is to not have a scrollbar appear temporarily during the animation, if there's not going to be one in the completed animated state. |
|
@guidezpl I was thinking the same thing. Fix is pushed. |
…eDryLayout (flutter#176503) _RenderDropdownMenuBody.computeDryLayout accesses this.constraints, but it should only access the constraints parameter passed into computeDryLayout. This PR removes this.constraints access. <img width="621" height="73" alt="image" src="proxy.php?url=https://github.com/user-attachments/assets/495573e3-3b91-4091-8a7c-76594c98e22f" /> Also, I removed a line in which the child's offset is being set in computeDryLayout. This appears to be an error: <img width="402" height="56" alt="image" src="proxy.php?url=https://github.com/user-attachments/assets/0045761d-c958-451b-a6ec-cbdf0fe7bd09" /> Finally, I'm curious whether there is a reason why only the first child is being used to set the height? Resolves flutter#176494 Blocking flutter#176494 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
QuncCccccc
left a comment
There was a problem hiding this comment.
LGTM. Thanks a lot for implementing this feature!
| /// Whether the menu should open and close with an animation. | ||
| /// | ||
| /// Defaults to false. | ||
| final bool animated; |
There was a problem hiding this comment.
Do we need to add onAnimationStatusChanged to SubmenuButton since it can also be treated like a "anchor"? But it's fine to add it when we need it in the future😄
There was a problem hiding this comment.
Done and added tests
|
Okay, everything should be updated. Added:
Changed:
Everything should be good-to-go, but I wanted one last check since I changed a few lines. Lmk and I'll merge! |
| /// Because the [MenuController.isOpen] property is true while the menu is | ||
| /// opening, opened, and closing, it cannot be used to determine whether the | ||
| /// menu is closing or opening. As such, this callback provides a way to | ||
| /// determine when the menu is opening or closing, and allows anchors to | ||
| /// toggle between the opening and closing states of the menu. |
There was a problem hiding this comment.
I find the first sentence taking a bit effort to understand due to the change of subject and the "it". I propose the following rewrite (with the help of AI).
| /// Because the [MenuController.isOpen] property is true while the menu is | |
| /// opening, opened, and closing, it cannot be used to determine whether the | |
| /// menu is closing or opening. As such, this callback provides a way to | |
| /// determine when the menu is opening or closing, and allows anchors to | |
| /// toggle between the opening and closing states of the menu. | |
| /// This callback provides a way to determine when the menu is opening or | |
| /// closing. This is necessary because the [MenuController.isOpen] property | |
| /// remains true throughout the opening, opened, and closing phases, and | |
| /// therefore cannot be used on its own to determine the current animation | |
| /// direction. |
There was a problem hiding this comment.
Done. Copied verbatim
| await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); | ||
| expect(focusedMenu, equals('MenuItemButton(Text("Sub Menu 12"))')); | ||
| }); | ||
| testWidgets('hoverOpenDelay delays when a SubmenuButton opens', (WidgetTester tester) async { |
There was a problem hiding this comment.
| testWidgets('hoverOpenDelay delays when a SubmenuButton opens', (WidgetTester tester) async { | |
| testWidgets('hoverOpenDelay delays when a SubmenuButton opens', (WidgetTester tester) async { |
| ), | ||
| ); | ||
| }, | ||
| experimentalLeakTesting: LeakTesting.settings |
There was a problem hiding this comment.
I think the convention, according to other tests, is to place this property before the test body.
QuncCccccc
left a comment
There was a problem hiding this comment.
LGTM. Thanks for your contribution:)!
There was a problem hiding this comment.
nit: We can also mention that this example also shows how to use [onAnimationStatusChanged] to track animation status and toggle the menu.
There was a problem hiding this comment.
Done -- copied verbatim
Roll Flutter from dfd92b773219 to da72d5936d69 (39 revisions) flutter/flutter@dfd92b7...da72d59 2026-01-29 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[ Tool / Engine ] Cleanup x86 references (#181152)" (flutter/flutter#181643) 2026-01-29 [email protected] Roll Skia from 174db42b7300 to 89df65f8324c (2 revisions) (flutter/flutter#181636) 2026-01-29 [email protected] [material/menu_anchor.dart] Add animations to MenuAnchor. (flutter/flutter#176494) 2026-01-28 [email protected] Roll Skia from 8e09f8a82251 to 174db42b7300 (6 revisions) (flutter/flutter#181627) 2026-01-28 [email protected] Send statusBarTouch events via dedicated messages (flutter/flutter#179643) 2026-01-28 [email protected] test: Improve DropdownMenuFormField tests (flutter/flutter#181369) 2026-01-28 [email protected] Account for vec3 padding in Metal (flutter/flutter#181563) 2026-01-28 [email protected] [ Tool / Engine ] Cleanup x86 references (flutter/flutter#181152) 2026-01-28 [email protected] Fix the issue on macOS where, after a hot restart with multiple windows, unresponsive windows are left behind. (flutter/flutter#180287) 2026-01-28 [email protected] Roll Skia from 675444e94bc9 to 8e09f8a82251 (7 revisions) (flutter/flutter#181606) 2026-01-28 [email protected] Roll Packages from e37af11 to 1cb2148 (5 revisions) (flutter/flutter#181608) 2026-01-28 [email protected] fix: swap app and engine version in vk::ApplicationInfo (flutter/flutter#181432) 2026-01-28 [email protected] Adds impeller backend to skia gold client (flutter/flutter#181503) 2026-01-28 [email protected] Remove chrome_and_driver dependency where it's not needed (flutter/flutter#178174) 2026-01-28 [email protected] chore: Windows_mokey basic_material_app_win__compile !bringup (flutter/flutter#180985) 2026-01-28 [email protected] Fix generating both `settings.gradle` and `settings.gradle.kts` for plugins (flutter/flutter#181592) 2026-01-28 [email protected] Roll Skia from 6614f89de521 to 675444e94bc9 (3 revisions) (flutter/flutter#181587) 2026-01-28 [email protected] Fix `todayBorder` todayBorder color is incorrectly overridden by `todayForegroundColor` in CalendarDatePicker (flutter/flutter#178792) 2026-01-28 [email protected] Roll Skia from 8f1695a4b328 to 6614f89de521 (2 revisions) (flutter/flutter#181583) 2026-01-28 [email protected] feat: add RoundedSuperellipseInputBorder (flutter/flutter#177220) 2026-01-28 [email protected] Roll Dart SDK from 38e351498549 to f10dcbfca98f (2 revisions) (flutter/flutter#181582) 2026-01-28 [email protected] Roll Skia from f424d58e37a3 to 8f1695a4b328 (6 revisions) (flutter/flutter#181577) 2026-01-28 [email protected] Remove unused code paths in `PlatformViewsController.java` (flutter/flutter#181393) 2026-01-28 [email protected] feat: add onEnd to AnimatedCrossFade (flutter/flutter#181455) 2026-01-28 [email protected] Don't pass bounds to saveLayer call when painting ImageFilter (flutter/flutter#181353) 2026-01-28 [email protected] test: Clarify failure messages on gestures/debug_test.dart (flutter/flutter#181109) 2026-01-27 [email protected] Roll Fuchsia Linux SDK from akraNGn2lw4T1msgZ... to adhoq9ouVRh0xzkm3... (flutter/flutter#181571) 2026-01-27 [email protected] Roll Dart SDK from 4c7cb0a1d07d to 38e351498549 (4 revisions) (flutter/flutter#181570) 2026-01-27 [email protected] Make sure that an AnimatedPadding doesn't crash in 0x0 environment (flutter/flutter#181235) 2026-01-27 [email protected] Make sure that an ImageFiltered doesn't crash at 0x0 environment (flutter/flutter#181067) 2026-01-27 [email protected] Marks firebase_release_smoke_test to be unflaky (flutter/flutter#181308) 2026-01-27 [email protected] Fix remove material import box decoration test (flutter/flutter#181253) 2026-01-27 [email protected] Roll Skia from c2754838b077 to f424d58e37a3 (8 revisions) (flutter/flutter#181564) 2026-01-27 [email protected] Make sure that an AnimatedAlign doesn't crash in 0x0 environment (flutter/flutter#181361) 2026-01-27 [email protected] Make sure that an ImageIcon doesn't crash in 0x0 environment (flutter/flutter#181099) 2026-01-27 [email protected] Make sure that an AnimatedContainer doesn't crash in 0x0 environment (flutter/flutter#181198) 2026-01-27 [email protected] Make sure that an AnimatedRotation doesn't crash in 0x0 environment (flutter/flutter#181486) 2026-01-27 [email protected] Make sure that an AnimatedPositionedDirectional doesn't crash in 0x0 … (flutter/flutter#181451) 2026-01-27 [email protected] Merge changelog for 3.38.8. (flutter/flutter#181558) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. ...
…6494) * Adds MD3 animations to MenuAnchor. * Adds a "hoverOpenDelay" parameter on `SubmenuButton` * Moves the layout algorithm from SingleChildLayoutDelegate to a custom render object. <s>This was done because I needed to access the dry layout of the menu panel for the best effect. I'll demonstrate below.</s> Turns out using dry layout significantly limits what children you can use with a widget. As a result, I'm calculating the final height using the inverse height factor. Fixes flutter#135025 I don't have access to the internal Google documentation, so I did my best to deduce the spec from https://github.com/material-components/material-web/blob/main/menu/internal/menu.ts. This change is currently opt-in via an `animated` parameter on `MenuAnchor` and `SubmenuButton`. As a result, this is not a breaking change. Because the PR is already quite large, I chose to not add animation customization to this PR. I also didn't change any theming files or `DropdownMenu`. The only other API addition is a `hoverOpenDelay` parameter on `SubmenuButton`. This parameter delays the start of a submenu opening by the specified duration. It is independent of the `animated` parameter. When `animated == false`, the menu runs its forward and reverse animations with a duration of 0. I originally disposed of all animation assets when `animated` was false, but found that the code/testing complexity to be unwieldy. <s>Blocked by https://github.com/flutter/flutter/pull/176503</s> ## Examples * Basic example adapted from material-web https://github.com/user-attachments/assets/e6d02fab-e11c-4dce-ab82-2fb39c1111e0 * Example showing scrollbar https://github.com/user-attachments/assets/847054ba-7218-4e73-9835-019bfa7b5521 * MenuBar usage https://github.com/user-attachments/assets/8231b1cd-c40c-4f18-af87-1b77b43ecb7b Thanks to @QuncCccccc and @dkwingsmt for [their work on this issue.](flutter#143416) Sorry for throwing a wrench into the original PR by introducing `RawMenuAnchor`... ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
SubmenuButtonThis was done because I needed to access the dry layout of the menu panel for the best effect. I'll demonstrate below.Turns out using dry layout significantly limits what children you can use with a widget. As a result, I'm calculating the final height using the inverse height factor.Fixes #135025
I don't have access to the internal Google documentation, so I did my best to deduce the spec from https://github.com/material-components/material-web/blob/main/menu/internal/menu.ts.
This change is currently opt-in via an
animatedparameter onMenuAnchorandSubmenuButton. As a result, this is not a breaking change. Because the PR is already quite large, I chose to not add animation customization to this PR. I also didn't change any theming files orDropdownMenu.The only other API addition is a
hoverOpenDelayparameter onSubmenuButton. This parameter delays the start of a submenu opening by the specified duration. It is independent of theanimatedparameter.When
animated == false, the menu runs its forward and reverse animations with a duration of 0. I originally disposed of all animation assets whenanimatedwas false, but found that the code/testing complexity to be unwieldy.Blocked by #176503Examples
Screen.Recording.2026-01-14.at.11.07.31.PM.mov
Screen.Recording.2026-01-14.at.11.08.26.PM.mov
Screen.Recording.2026-01-14.at.11.09.27.PM.mov
Thanks to @QuncCccccc and @dkwingsmt for their work on this issue. Sorry for throwing a wrench into the original PR by introducing
RawMenuAnchor...Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.