Repository navigation
Scrolling closes menuAnchor widget #122168
Copy link
Copy link
Closed
Labels
f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.found in release: 3.7Found to occur in 3.7Found to occur in 3.7found in release: 3.9Found to occur in 3.9Found to occur in 3.9frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesmaterial_ui package in flutter/packagesr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer version
Description
Screencast.from.2023-03-08.04-54-02.webm
Happens on both stable and master
flutter doctor:
[!] Flutter (Channel master, 3.9.0-1.0.pre.92, on Fedora Linux 37 (Workstation Edition) 6.1.11-200.fc37.x86_64, locale en_GB.UTF-8)
• Flutter version 3.9.0-1.0.pre.92 on channel master at /home/henryr/Dev/Github/Flutter/flutter
! Upstream repository https://github.com/whiskeyPeak/flutter.git is not a standard remote.
Set environment variable "FLUTTER_GIT_URL" to https://github.com/whiskeyPeak/flutter.git to dismiss this error.
• Framework revision 5a279edc23 (3 hours ago), 2023-03-07 21:24:23 -0500
• Engine revision 694a14ca6e
• Dart version 3.0.0 (build 3.0.0-308.0.dev)
• DevTools version 2.22.2
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks
and upgrades.
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
• Android SDK at /home/henryr/Android/Sdk
• Platform android-33-ext4, build-tools 33.0.2
• Java binary at: /home/henryr/Dev/SDK/Android Studio/android-studio/jbr/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Linux toolchain - develop for Linux desktop
• clang version 15.0.7 (Fedora 15.0.7-1.fc37)
• cmake version 3.25.2
• ninja version 1.10.2
• pkg-config version 1.8.0
[✓] Android Studio (version 2022.1)
• Android Studio at /home/henryr/Dev/SDK/Android Studio/android-studio
• Flutter plugin version 72.0.2
• Dart plugin version 221.6096
• Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
[✓] Connected device (2 available)
• Linux (desktop) • linux • linux-x64 • Fedora Linux 37 (Workstation Edition) 6.1.11-200.fc37.x86_64
• Chrome (web) • chrome • web-javascript • Google Chrome 110.0.5481.100
[✓] Network resources
• All expected network resources are available.
Repro code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
//colorScheme: const ColorScheme.dark(),
),
home: const Directionality(
textDirection: TextDirection.ltr,
child: MyHomePage(title: 'Flutter Demo Home Page')),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(MediaQuery.of(context).size.height.toString()),
centerTitle: true,
),
body: const Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
ButtonAnchorExample(),
Expanded(child: SizedBox()),
],
),
Column(
children: [
Expanded(child: SizedBox()),
ButtonAnchorExample(),
],
),
],
),
);
}
}
class ButtonAnchorExample extends StatelessWidget {
const ButtonAnchorExample({super.key});
@override
Widget build(BuildContext context) {
return MenuAnchor(
style: const MenuStyle(
//maximumSize: MaterialStateProperty.all(const Size(500, 200)),
visualDensity: VisualDensity.compact,
//alignment: AlignmentDirectional.topEnd
),
// This offset is not correct when menu direction is reversed
alignmentOffset: const Offset(0, 10),
builder: (context, controller, child) {
return FilledButton.tonal(
onPressed: () {
if (controller.isOpen) {
controller.close();
} else {
controller.open();
}
},
child: const Text('Show menu'),
);
},
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
SubmenuButton(
trailingIcon: const Icon(Icons.add),
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon:
const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon:
const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
],
child: const Text("SubMenuButton"),
),
SubmenuButton(
menuStyle: const MenuStyle(
visualDensity: VisualDensity.compact,
),
alignmentOffset: const Offset(8, 0),
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.people_alt_outlined),
child: const Text('Item 1'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.remove_red_eye_outlined),
child: const Text('Item 2'),
onPressed: () {},
),
MenuItemButton(
leadingIcon: const Icon(Icons.refresh),
onPressed: () {},
child: const Text('Item 3'),
),
],
child: const Text("SubMenuButton"),
),
],
);
}
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.found in release: 3.7Found to occur in 3.7Found to occur in 3.7found in release: 3.9Found to occur in 3.9Found to occur in 3.9frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesmaterial_ui package in flutter/packagesr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer version
Type
Projects
- StatusShow more project fieldsDone (PR merged)
Activity
whiskeyPeak commentedon Mar 8, 2023
In menu_anchor.dart line 465
@gspencergoog Could you explain to me what the use of this functions is? As things are right now, any kind of scrolling on the topLevel menu will automatically close it which is a little jarring and may seem like a bug to users.
Completely removing this function makes the UI behave the exact same way as if we only closed the menus after having checked for _isRoot being true. IMO this can probably be removed since it introduces a "bug" and doesn't really change the behaviour of the UI.
wdyt?
[-]Scrolling with touchpad closes menuAnchor widget[/-][+]Scrolling closes menuAnchor widget[/+]danagbemava-nc commentedon Mar 8, 2023
The issue is reproducible using the code sample provided above.
Steps to reproduce
show menubuttonsThis issue is not limited to desktop platforms only. The bug also reproduces when you make the mobile screen small enough and attempt to scroll. On android, you can achieve this by using the split screen feature.
recording on android
telegram-cloud-document-4-5782736726019543174.mp4
flutter doctor -v
bleroux commentedon Mar 15, 2023
@whiskeyPeak Many thanks for the detailed report!
I filed a PR, #122696. After investigation, I reached the same conclusion that you did: "As things are right now, any kind of scrolling on the topLevel menu will automatically close it " (from #122168 (comment))
github-actions commentedon Mar 29, 2023
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.