Prevent dropdown menu's scroll offset from going negative (#22235)
In long lists this resulted in the dropdown scrolling to the very last item in its list. Now clamping the value at `0.0`. Added a test to verify that the selected item aligns with the button to test the offset. Fixes flutter/flutter#15346
This commit is contained in:
parent
63f2fb9f5d
commit
020fd590b0
@ -346,9 +346,8 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scrollController == null) {
|
if (scrollController == null) {
|
||||||
double scrollOffset = 0.0;
|
final double scrollOffset = (preferredMenuHeight > maxMenuHeight) ?
|
||||||
if (preferredMenuHeight > maxMenuHeight)
|
math.max(0.0, selectedItemOffset - (buttonTop - menuTop)) : 0.0;
|
||||||
scrollOffset = selectedItemOffset - (buttonTop - menuTop);
|
|
||||||
scrollController = ScrollController(initialScrollOffset: scrollOffset);
|
scrollController = ScrollController(initialScrollOffset: scrollOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +422,57 @@ void main() {
|
|||||||
checkSelectedItemTextGeometry(tester, 'two');
|
checkSelectedItemTextGeometry(tester, 'two');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Dropdown menu scrolls to first item in long lists', (WidgetTester tester) async {
|
||||||
|
// Open the dropdown menu
|
||||||
|
final Key buttonKey = UniqueKey();
|
||||||
|
await tester.pumpWidget(buildFrame(
|
||||||
|
buttonKey: buttonKey,
|
||||||
|
value: null, // nothing selected
|
||||||
|
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString())
|
||||||
|
));
|
||||||
|
await tester.tap(find.byKey(buttonKey));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pumpAndSettle(); // finish the menu animation
|
||||||
|
|
||||||
|
// Find the first item in the scrollable dropdown list
|
||||||
|
final Finder menuItemFinder = find.byType(Scrollable);
|
||||||
|
final RenderBox menuItemContainer = tester.renderObject<RenderBox>(menuItemFinder);
|
||||||
|
final RenderBox firstItem = tester.renderObject<RenderBox>(
|
||||||
|
find.descendant(of: menuItemFinder, matching: find.byKey(const ValueKey<String>('0'))));
|
||||||
|
|
||||||
|
// List should be scrolled so that the first item is at the top. Menu items
|
||||||
|
// are offset 8.0 from the top edge of the scrollable menu.
|
||||||
|
const Offset selectedItemOffset = Offset(0.0, -8.0);
|
||||||
|
expect(
|
||||||
|
firstItem.size.topCenter(firstItem.localToGlobal(selectedItemOffset)).dy,
|
||||||
|
equals(menuItemContainer.size.topCenter(menuItemContainer.localToGlobal(Offset.zero)).dy)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Dropdown menu aligns selected item with button in long lists', (WidgetTester tester) async {
|
||||||
|
// Open the dropdown menu
|
||||||
|
final Key buttonKey = UniqueKey();
|
||||||
|
await tester.pumpWidget(buildFrame(
|
||||||
|
buttonKey: buttonKey,
|
||||||
|
value: '50',
|
||||||
|
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString())
|
||||||
|
));
|
||||||
|
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
|
await tester.tap(find.byKey(buttonKey));
|
||||||
|
await tester.pumpAndSettle(); // finish the menu animation
|
||||||
|
|
||||||
|
// Find the selected item in the scrollable dropdown list
|
||||||
|
final RenderBox selectedItem = tester.renderObject<RenderBox>(
|
||||||
|
find.descendant(of: find.byType(Scrollable), matching: find.byKey(const ValueKey<String>('50'))));
|
||||||
|
|
||||||
|
// List should be scrolled so that the selected item is in line with the button
|
||||||
|
expect(
|
||||||
|
selectedItem.size.center(selectedItem.localToGlobal(Offset.zero)).dy,
|
||||||
|
equals(buttonBox.size.center(buttonBox.localToGlobal(Offset.zero)).dy)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
testWidgets('Size of DropdownButton with null value', (WidgetTester tester) async {
|
testWidgets('Size of DropdownButton with null value', (WidgetTester tester) async {
|
||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
String value;
|
String value;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user