diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index 28c93becb04..611802afc85 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -23,6 +23,7 @@ import 'colors.dart'; import 'constants.dart'; import 'debug.dart'; import 'icons.dart'; +import 'ink_decoration.dart'; import 'ink_well.dart'; import 'input_decorator.dart'; import 'material.dart'; @@ -217,14 +218,22 @@ class _DropdownMenuItemButtonState extends State<_DropdownMenuItemButton> child = Padding(padding: padding, child: child); } child = SizedBox(height: widget.route.itemHeight, child: child); + + final bool isSelected = widget.itemIndex == widget.route.selectedIndex; + final FocusHighlightMode highlightMode = FocusManager.instance.highlightMode; // An [InkWell] is added to the item only if it is enabled if (dropdownMenuItem.enabled) { child = InkWell( - autofocus: widget.itemIndex == widget.route.selectedIndex, + autofocus: isSelected, enableFeedback: widget.enableFeedback, onTap: _handleOnTap, onFocusChange: _handleFocusChange, - child: child, + // When highlightMode is traditional, the InkWell draws the selected item background color. + // When highlightMode is touch, insert an Ink to force the selected item background color. + child: + highlightMode == FocusHighlightMode.touch + ? Ink(color: isSelected ? Theme.of(context).focusColor : null, child: child) + : child, ); } child = FadeTransition(opacity: _opacityAnimation, child: child); diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index bf4545878f3..88bc2693815 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -4449,4 +4449,67 @@ void main() { // The dropdown should still be open, i.e., there should be one widget with 'second' text. expect(find.text('second'), findsOneWidget); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/70294. + testWidgets( + 'The previous selected item should be highlighted when reopening dropdown on mobile', + (WidgetTester tester) async { + final Color selectedColor = Colors.black.withValues(alpha: 0.12); + String currentValue = 'one'; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(focusColor: selectedColor), + home: Scaffold( + body: Center( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return DropdownButton( + value: currentValue, + items: + menuItems + .map( + (String item) => + DropdownMenuItem(value: item, child: Text(item)), + ) + .toList(), + onChanged: (String? newValue) { + setState(() { + currentValue = newValue!; + }); + }, + ); + }, + ), + ), + ), + ), + ); + + // Make sure the current value of dropdown is the first one of items list menuItems. + expect(find.text('one'), findsOne); + + // Tap to open the dropdown. + await tester.tap(find.text('one')); + await tester.pumpAndSettle(); + + // Select the second item from the dropdown list. + await tester.tap(find.text('two')); + await tester.pumpAndSettle(); + + // Make sure the current item of dropdown is the second item of items list menuItems. + expect(find.text('two'), findsOneWidget); + + // Tap to reopen the dropdown. + await tester.tap(find.text('two')); + await tester.pumpAndSettle(); + + // Make sure the current selected item is highlighted with selectedColor. + final Ink selectedItemInk = tester.widget( + find.ancestor(of: find.text('two'), matching: find.byType(Ink)).first, + ); + final BoxDecoration decoration = selectedItemInk.decoration! as BoxDecoration; + expect(decoration.color, selectedColor); + }, + variant: TargetPlatformVariant.mobile(), + ); }