Fix DropdownMenu isCollapsed decoration does not Reduce height (#161427)
## Description This PR fixes DropdownMenu arrow icon position when `InputDecoration.isCollapsed` is set to true and `InputDecoration.suffixConstraints` is set to a smaller value than the min interactive height. It makes it possible to use collapsed `DropdownMenu` such as:  _____ Before this PR and https://github.com/flutter/flutter/pull/153089, `InputDecoration.isCollapsed` had no impact on the `DropdownMenu` height and there was no solution to reduce the height because its minimum height is enforced by the `IconButton` (arrow down or up) which is part of the `DropdownMenu`. Since https://github.com/flutter/flutter/pull/153089, the height can be reduce with `InputDecoration.suffixIconConstraints` but it results in the icon being misaligned:  After this PR: When `InputDecoration.suffixIconConstraints` is used the icon is correctly aligned:  <details><summary>Code sample</summary> ```dart import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( title: 'Flutter Demo', home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return const Scaffold( body: Center( child: Center( child: DropdownMenu<String>( dropdownMenuEntries: [ DropdownMenuEntry(label: 'Item 1', value: '1'), DropdownMenuEntry(label: 'Item 2', value: '2'), ], inputDecorationTheme: InputDecorationTheme( contentPadding: EdgeInsets.fromLTRB(5, 0, 5, 0), isCollapsed: true, // Usable since https://github.com/flutter/flutter/pull/153089. suffixIconConstraints: BoxConstraints(minHeight: 24, maxHeight: 24), filled: true, ), ), ), ), ); } } ``` </details> ## Related Issue Fixes [DropdownMenu inputDecoration isCollapsed property does not reduce vertical spacing](https://github.com/flutter/flutter/issues/138691) ## Tests Adds 2 tests.
This commit is contained in:
@@ -965,10 +965,13 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
||||
crossAxisUnconstrained: false,
|
||||
builder: (BuildContext context, MenuController controller, Widget? child) {
|
||||
assert(_initialMenu != null);
|
||||
final bool isCollapsed = widget.inputDecorationTheme?.isCollapsed ?? false;
|
||||
final Widget trailingButton = Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
padding: isCollapsed ? EdgeInsets.zero : const EdgeInsets.all(4.0),
|
||||
child: IconButton(
|
||||
isSelected: controller.isOpen,
|
||||
constraints: widget.inputDecorationTheme?.suffixIconConstraints,
|
||||
padding: isCollapsed ? EdgeInsets.zero : null,
|
||||
icon: widget.trailingIcon ?? const Icon(Icons.arrow_drop_down),
|
||||
selectedIcon: widget.selectedTrailingIcon ?? const Icon(Icons.arrow_drop_up),
|
||||
onPressed:
|
||||
|
||||
@@ -46,6 +46,7 @@ void main() {
|
||||
double? menuHeight,
|
||||
Widget? leadingIcon,
|
||||
Widget? label,
|
||||
InputDecorationTheme? decorationTheme,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: themeData,
|
||||
@@ -56,6 +57,7 @@ void main() {
|
||||
width: width,
|
||||
menuHeight: menuHeight,
|
||||
dropdownMenuEntries: entries,
|
||||
inputDecorationTheme: decorationTheme,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -1172,6 +1174,71 @@ void main() {
|
||||
expect(iconButton, findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Trailing IconButton height respects InputDecorationTheme.suffixIconConstraints', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final ThemeData themeData = ThemeData();
|
||||
|
||||
// Default suffix icon constraints.
|
||||
await tester.pumpWidget(buildTest(themeData, menuChildren));
|
||||
await tester.pump();
|
||||
|
||||
final Finder iconButton = find.widgetWithIcon(IconButton, Icons.arrow_drop_down).first;
|
||||
expect(tester.getSize(iconButton), const Size(48, 48));
|
||||
|
||||
// Custom suffix icon constraints.
|
||||
await tester.pumpWidget(
|
||||
buildTest(
|
||||
themeData,
|
||||
menuChildren,
|
||||
decorationTheme: const InputDecorationTheme(
|
||||
suffixIconConstraints: BoxConstraints(minWidth: 66, minHeight: 62),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(iconButton), const Size(66, 62));
|
||||
});
|
||||
|
||||
testWidgets('InputDecorationTheme.isCollapsed reduces height', (WidgetTester tester) async {
|
||||
final ThemeData themeData = ThemeData();
|
||||
|
||||
// Default height.
|
||||
await tester.pumpWidget(buildTest(themeData, menuChildren));
|
||||
await tester.pump();
|
||||
|
||||
final Finder textField = find.byType(TextField).first;
|
||||
expect(tester.getSize(textField).height, 56);
|
||||
|
||||
// Collapsed height.
|
||||
await tester.pumpWidget(
|
||||
buildTest(
|
||||
themeData,
|
||||
menuChildren,
|
||||
decorationTheme: const InputDecorationTheme(isCollapsed: true),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(textField).height, 48); // IconButton min height.
|
||||
|
||||
// Collapsed height with custom suffix icon constraints.
|
||||
await tester.pumpWidget(
|
||||
buildTest(
|
||||
themeData,
|
||||
menuChildren,
|
||||
decorationTheme: const InputDecorationTheme(
|
||||
isCollapsed: true,
|
||||
suffixIconConstraints: BoxConstraints(maxWidth: 24, maxHeight: 24),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(textField).height, 24);
|
||||
});
|
||||
|
||||
testWidgets('Do not crash when resize window during menu opening', (WidgetTester tester) async {
|
||||
addTearDown(tester.view.reset);
|
||||
final ThemeData themeData = ThemeData();
|
||||
|
||||
Reference in New Issue
Block a user