Unverified Commit 6dc3bfaa authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

Fix Dropdown `'itemHeights' was called on null` crash (#50366)

parent 95d6ef74
......@@ -1143,6 +1143,17 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
menuItems[index] = _MenuItem<T>(
item: widget.items[index],
onLayout: (Size size) {
// If [_dropdownRoute] is null and onLayout is called, this means
// that performLayout was called on a _DropdownRoute that has not
// left the widget tree but is already on its way out.
//
// Since onLayout is used primarily to collect the desired heights
// of each menu item before laying them out, not having the _DropdownRoute
// collect each item's height to lay out is fine since the route is
// already on its way out.
if (_dropdownRoute == null)
return;
_dropdownRoute.itemHeights[index] = size.height;
},
);
......@@ -1162,7 +1173,7 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
);
Navigator.push(context, _dropdownRoute).then<void>((_DropdownRouteResult<T> newValue) {
_dropdownRoute = null;
_removeDropdownRoute();
if (!mounted || newValue == null)
return;
if (widget.onChanged != null)
......
......@@ -1915,6 +1915,62 @@ void main() {
expect(tester.getCenter(item40.first).dy, tester.getCenter(item40.last).dy);
});
testWidgets('DropdownButton menu items do not resize when its route is popped', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/44877.
const List<String> items = <String>[
'one',
'two',
'three',
];
String item = items[0];
MediaQueryData mediaQuery;
await tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return MaterialApp(
builder: (BuildContext context, Widget child) {
mediaQuery ??= MediaQuery.of(context);
return MediaQuery(
data: mediaQuery,
child: child,
);
},
home: Scaffold(
body: DropdownButton<String>(
value: item,
items: items.map((String item) => DropdownMenuItem<String>(
value: item,
child: Text(item),
)).toList(),
onChanged: (String newItem) {
setState(() {
item = newItem;
mediaQuery = mediaQuery.copyWith(
textScaleFactor: mediaQuery.textScaleFactor + 0.1,
);
});
},
),
),
);
},
),
);
// Verify that the first item is showing.
expect(find.text('one'), findsOneWidget);
// Select a different item to trigger setState, which updates mediaQuery
// and forces a performLayout on the popped _DropdownRoute. This operation
// should not cause an exception.
await tester.tap(find.text('one'));
await tester.pumpAndSettle();
await tester.tap(find.text('two').last);
await tester.pumpAndSettle();
expect(find.text('two'), findsOneWidget);
});
testWidgets('DropdownButton hint is selected item', (WidgetTester tester) async {
const double hintPaddingOffset = 8;
const List<String> itemValues = <String>['item0', 'item1', 'item2', 'item3'];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment