Fix DropdownMenu does not rematch initialSelection when entries have changed (#155757)
## Description This PR makes DropdownMenu rematching the initialSelection when the entries are updated. If the new entries contains one entry whose value matches `initialSelection` this entry's label is used to initialize the inner text field, if no entries matches `initialSelection` the text field is emptied. ## Related Issue Fixes [DropdownMenu.didUpdateWidget should re-match initialSelection when dropdownMenuEntries have changed](https://github.com/flutter/flutter/issues/155660). ## Tests Adds 3 tests.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Flutter code sample for [DropdownMenu]s. The first dropdown menu
|
||||
@@ -14,6 +15,8 @@ void main() {
|
||||
runApp(const DropdownMenuExample());
|
||||
}
|
||||
|
||||
typedef ColorEntry = DropdownMenuEntry<ColorLabel>;
|
||||
|
||||
// DropdownMenuEntry labels and values for the first dropdown menu.
|
||||
enum ColorLabel {
|
||||
blue('Blue', Colors.blue),
|
||||
@@ -25,21 +28,43 @@ enum ColorLabel {
|
||||
const ColorLabel(this.label, this.color);
|
||||
final String label;
|
||||
final Color color;
|
||||
|
||||
static final List<ColorEntry> entries = UnmodifiableListView<ColorEntry>(
|
||||
values.map<ColorEntry>(
|
||||
(ColorLabel color) => ColorEntry(
|
||||
value: color,
|
||||
label: color.label,
|
||||
enabled: color.label != 'Grey',
|
||||
style: MenuItemButton.styleFrom(
|
||||
foregroundColor: color.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
typedef IconEntry = DropdownMenuEntry<IconLabel>;
|
||||
|
||||
// DropdownMenuEntry labels and values for the second dropdown menu.
|
||||
enum IconLabel {
|
||||
smile('Smile', Icons.sentiment_satisfied_outlined),
|
||||
cloud(
|
||||
'Cloud',
|
||||
Icons.cloud_outlined,
|
||||
),
|
||||
cloud('Cloud', Icons.cloud_outlined),
|
||||
brush('Brush', Icons.brush_outlined),
|
||||
heart('Heart', Icons.favorite);
|
||||
|
||||
const IconLabel(this.label, this.icon);
|
||||
final String label;
|
||||
final IconData icon;
|
||||
|
||||
static final List<IconEntry> entries = UnmodifiableListView<IconEntry>(
|
||||
values.map<IconEntry>(
|
||||
(IconLabel icon) => IconEntry(
|
||||
value: icon,
|
||||
label: icon.label,
|
||||
leadingIcon: Icon(icon.icon),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class DropdownMenuExample extends StatefulWidget {
|
||||
@@ -85,18 +110,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
selectedColor = color;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries: ColorLabel.values.map<DropdownMenuEntry<ColorLabel>>(
|
||||
(ColorLabel color) {
|
||||
return DropdownMenuEntry<ColorLabel>(
|
||||
value: color,
|
||||
label: color.label,
|
||||
enabled: color.label != 'Grey',
|
||||
style: MenuItemButton.styleFrom(
|
||||
foregroundColor: color.color,
|
||||
),
|
||||
);
|
||||
}
|
||||
).toList(),
|
||||
dropdownMenuEntries: ColorLabel.entries,
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
DropdownMenu<IconLabel>(
|
||||
@@ -114,15 +128,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
selectedIcon = icon;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries: IconLabel.values.map<DropdownMenuEntry<IconLabel>>(
|
||||
(IconLabel icon) {
|
||||
return DropdownMenuEntry<IconLabel>(
|
||||
value: icon,
|
||||
label: icon.label,
|
||||
leadingIcon: Icon(icon.icon),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
dropdownMenuEntries: IconLabel.entries,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [DropdownMenu].
|
||||
@@ -34,7 +35,12 @@ class DropdownMenuExample extends StatefulWidget {
|
||||
State<DropdownMenuExample> createState() => _DropdownMenuExampleState();
|
||||
}
|
||||
|
||||
typedef MenuEntry = DropdownMenuEntry<String>;
|
||||
|
||||
class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
static final List<MenuEntry> menuEntries = UnmodifiableListView<MenuEntry>(
|
||||
list.map<MenuEntry>((String name) => MenuEntry(value: name, label: name)),
|
||||
);
|
||||
String dropdownValue = list.first;
|
||||
|
||||
@override
|
||||
@@ -47,12 +53,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
dropdownValue = value!;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries: list.map<DropdownMenuEntry<String>>((String value) {
|
||||
return DropdownMenuEntry<String>(
|
||||
value: value,
|
||||
label: value
|
||||
);
|
||||
}).toList(),
|
||||
dropdownMenuEntries: menuEntries,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [DropdownMenu].
|
||||
@@ -33,7 +34,12 @@ class DropdownMenuExample extends StatefulWidget {
|
||||
State<DropdownMenuExample> createState() => _DropdownMenuExampleState();
|
||||
}
|
||||
|
||||
typedef MenuEntry = DropdownMenuEntry<String>;
|
||||
|
||||
class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
static final List<MenuEntry> menuEntries = UnmodifiableListView<MenuEntry>(
|
||||
list.map<MenuEntry>((String name) => MenuEntry(value: name, label: name)),
|
||||
);
|
||||
String dropdownValue = list.first;
|
||||
|
||||
@override
|
||||
@@ -62,10 +68,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
dropdownValue = value!;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries:
|
||||
list.map<DropdownMenuEntry<String>>((String value) {
|
||||
return DropdownMenuEntry<String>(value: value, label: value);
|
||||
}).toList(),
|
||||
dropdownMenuEntries: menuEntries,
|
||||
),
|
||||
const Text('Text cursor is shown when hovering over the DropdownMenu.'),
|
||||
],
|
||||
@@ -92,10 +95,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
dropdownValue = value!;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries:
|
||||
list.map<DropdownMenuEntry<String>>((String value) {
|
||||
return DropdownMenuEntry<String>(value: value, label: value);
|
||||
}).toList(),
|
||||
dropdownMenuEntries: menuEntries,
|
||||
),
|
||||
const Text('Clickable cursor is shown when hovering over the DropdownMenu.'),
|
||||
],
|
||||
@@ -123,10 +123,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
dropdownValue = value!;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries:
|
||||
list.map<DropdownMenuEntry<String>>((String value) {
|
||||
return DropdownMenuEntry<String>(value: value, label: value);
|
||||
}).toList(),
|
||||
dropdownMenuEntries: menuEntries,
|
||||
),
|
||||
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
|
||||
],
|
||||
@@ -154,10 +151,7 @@ class _DropdownMenuExampleState extends State<DropdownMenuExample> {
|
||||
dropdownValue = value!;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries:
|
||||
list.map<DropdownMenuEntry<String>>((String value) {
|
||||
return DropdownMenuEntry<String>(value: value, label: value);
|
||||
}).toList(),
|
||||
dropdownMenuEntries: menuEntries,
|
||||
),
|
||||
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user