Skip to content

[Material] showMenu() doesn't scroll initial item to visible  #142895

@tvolkert

Description

@tvolkert

Steps to reproduce

Run the following app and click to open the popup menu:

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: Scaffold(body: BugReport())));
}

class BugReport extends StatefulWidget {
  const BugReport({super.key});

  @override
  State<BugReport> createState() => _BugReportState();
}

class _BugReportState extends State<BugReport> {
  static const int _length = 50;

  List<PopupMenuEntry<int>> _buildItems(BuildContext context) {
    return List<PopupMenuEntry<int>>.generate(_length, (int index) {
      return PopupMenuItem<int>(value: index, child: Text('$index'));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(50),
      child: Align(
        alignment: Alignment.bottomCenter,
        child: PopupMenuButton(
          itemBuilder: _buildItems,
          initialValue: _length - 1,
          child: const Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text('Click here to open popup menu '),
              Icon(Icons.ads_click),
            ],
          ),
        ),
      ),
    );
  }
}

Expected behavior

You expect that since item 49 is initially selected, it will also be scrolled to visible.

Actual behavior

Although item 49 is correctly selected when you open the popup menu, the list of items is not scrolled at all, which means the user can't see that it's selected without scrolling to find it themselves, leading to a confusion experience.

Test reproduction

Once fixed, this test should pass (as of this filing, the test fails):

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('PopupMenuButton scrolls initial value to visible', (WidgetTester tester) async {
    const int length = 50;
    await tester.pumpWidget(
      MaterialApp(
        home: Scaffold(
          body: Align(
            alignment: Alignment.bottomCenter,
            child: PopupMenuButton(
              itemBuilder: (BuildContext context) {
                return List<PopupMenuEntry<int>>.generate(length, (int index) {
                  return PopupMenuItem<int>(value: index, child: Text('item #$index'));
                });
              },
              popUpAnimationStyle: AnimationStyle.noAnimation,
              initialValue: length - 1,
              child: const Text('click here'),
            ),
          ),
        ),
      ),
    );
    await tester.tap(find.text('click here'));
    await tester.pump();

    // Set up finder and verify basic widget structure
    final Finder findSelectedItem = find.text('item #49');
    expect(findSelectedItem, findsOne);

    // The initially selected menu item should be positioned on screen
    final RenderBox selectedItem = tester.renderObject<RenderBox>(findSelectedItem);
    final Rect selectedItemBounds = selectedItem.localToGlobal(Offset.zero) & selectedItem.size;
    final Size windowSize = tester.view.physicalSize / tester.view.devicePixelRatio;
    expect(selectedItemBounds.bottomRight.dy, lessThanOrEqualTo(windowSize.height));
  });
}

Related issues

  1. [Material] showMenu() assumes the popup has an unconstrained height when it positions the popup #142896

Flutter version

[✓] Flutter (Channel main, 3.20.0-1.0.pre.20, on macOS 14.1 23B2073 darwin-arm64, locale en-US)
    • Flutter version 3.20.0-1.0.pre.20 on channel main at /Users/tvolkert/project/flutter/flutter
    • Upstream repository [email protected]:flutter/flutter.git
    • Framework revision f8a77225f3 (9 hours ago), 2024-02-04 14:28:18 +0000
    • Engine revision f34c658b96
    • Dart version 3.4.0 (build 3.4.0-99.0.dev)
    • DevTools version 2.31.0

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listf: material designflutter/packages/flutter/material repository.frameworkflutter/packages/flutter repository. See also f: labels.team-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions