Fix DropdownButton crash when viewport size is too small for the entirety of the menu's height (#76764)
This commit is contained in:
parent
fc77610dd6
commit
8d866d9c02
@ -65,12 +65,12 @@ class _DropdownMenuPainter extends CustomPainter {
|
|||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final double selectedItemOffset = getSelectedItemOffset();
|
final double selectedItemOffset = getSelectedItemOffset();
|
||||||
final Tween<double> top = Tween<double>(
|
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,
|
end: 0.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Tween<double> bottom = Tween<double>(
|
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,
|
end: size.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3008,4 +3008,61 @@ void main() {
|
|||||||
expect(scrollController.position.maxScrollExtent > 0, isTrue);
|
expect(scrollController.position.maxScrollExtent > 0, isTrue);
|
||||||
expect(find.byType(Scrollbar), paints..rect());
|
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)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user