Stop DropdownMenu internal scrolling from moving parent Scrollable (#153360)

fixes https://github.com/flutter/flutter/issues/151854
fixes #139113

The regression test uses nested `ListView` because I could not reproduce the issue without using nested `Scrollable`.

The issue is masked when there is only one `Scrollable` outside `DropdownMenu`. While `Scrollable.ensureVisible` can find all the `Scrollable`, the actual scrolling is performed by `ScrollPosition.ensureVisible` , which uses the `RenderObject` tree to find nearest Viewport but it could not find one due to `OverlayPortal` putting the target `RenderObject` at different point. So no scrolling will occur.

However when there are nested `Scrollable`, `Scrollable.ensureVisible` can scroll the outside `Scrollable` normally since no `RenderObject` tree gap exist between the two `Scrollable`
This commit is contained in:
PurplePolyhedron 2024-08-23 05:14:22 +08:00 committed by GitHub
parent e0cd56b52b
commit 8e50a17d94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View File

@ -592,7 +592,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final BuildContext? highlightContext = buttonItemKeys[currentHighlight!].currentContext; final BuildContext? highlightContext = buttonItemKeys[currentHighlight!].currentContext;
if (highlightContext != null) { if (highlightContext != null) {
Scrollable.ensureVisible(highlightContext); Scrollable.of(highlightContext).position.ensureVisible(highlightContext.findRenderObject()!);
} }
}, debugLabel: 'DropdownMenu.scrollToHighlight'); }, debugLabel: 'DropdownMenu.scrollToHighlight');
} }

View File

@ -2723,6 +2723,36 @@ void main() {
), ),
); );
}); });
// This is a regression test for https://github.com/flutter/flutter/issues/151854.
testWidgets('scrollToHighlight does not scroll parent', (WidgetTester tester) async {
final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: ListView(
controller: controller,
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[DropdownMenu<TestMenu>(
initialSelection: menuChildren.last.value,
dropdownMenuEntries: menuChildren,
)],
),
const SizedBox(height: 1000.0),
],
),
),
),
);
await tester.tap(find.byType(TextField).first);
await tester.pumpAndSettle();
expect(controller.offset, 0.0);
});
} }
enum TestMenu { enum TestMenu {