Fix DropdownButton crash when viewport size is too small for the entirety of the menu's height (#76764)

This commit is contained in:
xubaolin 2021-03-02 00:31:04 +08:00 committed by GitHub
parent fc77610dd6
commit 8d866d9c02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 2 deletions

View File

@ -65,12 +65,12 @@ class _DropdownMenuPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
final double selectedItemOffset = getSelectedItemOffset();
final Tween<double> top = Tween<double>(
begin: selectedItemOffset.clamp(0.0, size.height - _kMenuItemHeight),
begin: selectedItemOffset.clamp(0.0, math.max(size.height - _kMenuItemHeight, 0.0)),
end: 0.0,
);
final Tween<double> bottom = Tween<double>(
begin: (top.begin! + _kMenuItemHeight).clamp(_kMenuItemHeight, size.height),
begin: (top.begin! + _kMenuItemHeight).clamp(math.min(_kMenuItemHeight, size.height), size.height),
end: size.height,
);

View File

@ -3008,4 +3008,61 @@ void main() {
expect(scrollController.position.maxScrollExtent > 0, isTrue);
expect(find.byType(Scrollbar), paints..rect());
});
// Regression test for https://github.com/flutter/flutter/issues/76614
testWidgets('Do not crash if used in very short screen', (WidgetTester tester) async {
// The default item height is 48.0 pixels and needs two items padding since
// the menu requires empty space surrounding the menu. Finally, the constraint height
// is 47.0 pixels for the menu rendering.
tester.binding.window.physicalSizeTestValue = const Size(800.0, 48.0 * 3 - 1.0);
tester.binding.window.devicePixelRatioTestValue = 1;
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
addTearDown(tester.binding.window.clearDevicePixelRatioTestValue);
const String value = 'foo';
final UniqueKey itemKey = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton<String>(
value: value,
items: <DropdownMenuItem<String>>[
DropdownMenuItem<String>(
key: itemKey,
value: value,
child: const Text(value),
),
],
onChanged: (_) { },
),
),
),
),
);
await tester.tap(find.text(value));
await tester.pumpAndSettle();
final List<RenderBox> itemBoxes = tester.renderObjectList<RenderBox>(find.byKey(itemKey)).toList();
expect(itemBoxes[0].localToGlobal(Offset.zero).dx, 364.0);
expect(itemBoxes[0].localToGlobal(Offset.zero).dy, 47.5);
expect(itemBoxes[1].localToGlobal(Offset.zero).dx, 364.0);
expect(itemBoxes[1].localToGlobal(Offset.zero).dy, 47.5);
expect(
find.ancestor(
of: find.text(value).last,
matching: find.byType(CustomPaint),
).at(2),
paints
..save()
..rrect()
..rrect()
..rrect()
// The height of menu is 47.0.
..rrect(rrect: const RRect.fromLTRBXY(0.0, 0.0, 112.0, 47.0, 2.0, 2.0), color: Colors.grey[50], hasMaskFilter: false)
);
});
}